mirror of
https://github.com/snipe/snipe-it.git
synced 2024-11-09 23:24:06 -08:00
Merge branch 'develop' into snipeit_v7_laravel10
This commit is contained in:
commit
7a5714cc85
|
@ -1,44 +0,0 @@
|
|||
version: 1
|
||||
|
||||
environment:
|
||||
php: 8.0
|
||||
node: 12
|
||||
|
||||
services:
|
||||
- mysql: 5.7
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches: .*
|
||||
|
||||
pipeline:
|
||||
- name: Setup
|
||||
cmd: |
|
||||
cp -v .env.testing.example .env
|
||||
cp -v .env.testing.example .env.testing
|
||||
composer install --no-interaction --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Generate Key
|
||||
cmd: |
|
||||
php artisan key:generate --force
|
||||
|
||||
- name: Passport Keys
|
||||
cmd: |
|
||||
php artisan passport:keys
|
||||
|
||||
- name: Run Migrations
|
||||
cmd: |
|
||||
php artisan migrate --force
|
||||
|
||||
- name: PHPUnit Unit Tests
|
||||
cmd: |
|
||||
php artisan test --testsuite Unit
|
||||
|
||||
- name: PHPUnit Feature Tests
|
||||
cmd: |
|
||||
php artisan test --testsuite Feature
|
2
.github/autolabeler.yml
vendored
2
.github/autolabeler.yml
vendored
|
@ -18,5 +18,5 @@ importer: ["/app/Importer/*","/app/Http/Livewire/Importer.php", "resources/views
|
|||
cli / artisan: ["/app/Console/*"]
|
||||
LDAP: ["*Ldap*", "/app/Console/Commands/Ldap*","/app/Models/Ldap.php"]
|
||||
docker: ["*docker/*", "Dockerfile", "Dockerfile.alpine", "Dockerfile.fpm-alpine", ".dockerignore", ".env.docker"]
|
||||
tests: ["/tests/*", "/stubs"]
|
||||
tests: ["/tests/*", "/database/factories/*", "/stubs"]
|
||||
config: .github
|
||||
|
|
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
|
@ -2,5 +2,6 @@ version: 2
|
|||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "develop"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
|
2
.github/workflows/SA-codeql.yml
vendored
2
.github/workflows/SA-codeql.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
|||
language: [ 'javascript' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3.3.0
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
|
2
.github/workflows/codacy-analysis.yml
vendored
2
.github/workflows/codacy-analysis.yml
vendored
|
@ -32,7 +32,7 @@ jobs:
|
|||
steps:
|
||||
# Checkout the repository to the GitHub Actions runner
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3.3.0
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Run Codacy Analysis CLI
|
||||
|
|
2
.github/workflows/crowdin-upload.yml
vendored
2
.github/workflows/crowdin-upload.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Crowdin push
|
||||
uses: crowdin/github-action@v1
|
||||
|
|
11
.github/workflows/docker-alpine.yml
vendored
11
.github/workflows/docker-alpine.yml
vendored
|
@ -32,6 +32,7 @@ jobs:
|
|||
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }},suffix=-alpine
|
||||
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }},suffix=-alpine
|
||||
type=ref,event=tag,suffix=-alpine
|
||||
type=semver,pattern=v{{major}}-latest-alpine
|
||||
# Define default tag "flavor" for docker/metadata-action per
|
||||
# https://github.com/docker/metadata-action#flavor-input
|
||||
# We turn off 'latest' tag by default.
|
||||
|
@ -41,17 +42,17 @@ jobs:
|
|||
steps:
|
||||
# https://github.com/actions/checkout
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v3.3.0
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# https://github.com/docker/login-action
|
||||
- name: Login to DockerHub
|
||||
# Only login if not a PR, as PRs only trigger a Docker build and not a push
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
|
@ -63,7 +64,7 @@ jobs:
|
|||
# Get Metadata for docker_build step below
|
||||
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
|
||||
id: meta_build
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: snipe/snipe-it
|
||||
tags: ${{ env.IMAGE_TAGS }}
|
||||
|
@ -72,7 +73,7 @@ jobs:
|
|||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push 'snipe-it' image
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.alpine
|
||||
|
|
11
.github/workflows/docker.yml
vendored
11
.github/workflows/docker.yml
vendored
|
@ -32,6 +32,7 @@ jobs:
|
|||
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
|
||||
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern=v{{major}}-latest
|
||||
# Define default tag "flavor" for docker/metadata-action per
|
||||
# https://github.com/docker/metadata-action#flavor-input
|
||||
# We turn off 'latest' tag by default.
|
||||
|
@ -41,17 +42,17 @@ jobs:
|
|||
steps:
|
||||
# https://github.com/actions/checkout
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v3.3.0
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# https://github.com/docker/login-action
|
||||
- name: Login to DockerHub
|
||||
# Only login if not a PR, as PRs only trigger a Docker build and not a push
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
|
@ -63,7 +64,7 @@ jobs:
|
|||
# Get Metadata for docker_build step below
|
||||
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
|
||||
id: meta_build
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: snipe/snipe-it
|
||||
tags: ${{ env.IMAGE_TAGS }}
|
||||
|
@ -72,7 +73,7 @@ jobs:
|
|||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push 'snipe-it' image
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
|
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
@ -37,7 +37,7 @@ jobs:
|
|||
php-version: "${{ matrix.php-version }}"
|
||||
coverage: none
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Get Composer Cache Directory
|
||||
id: composer-cache
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
||||
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
||||
[![All Contributors](https://img.shields.io/badge/all_contributors-326-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
|
||||
|
||||
## Snipe-IT - Open Source Asset Management System
|
||||
|
|
|
@ -180,10 +180,6 @@ class LdapSync extends Command
|
|||
}
|
||||
}
|
||||
|
||||
/* Create user account entries in Snipe-IT */
|
||||
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20);
|
||||
$pass = bcrypt($tmp_pass);
|
||||
|
||||
$manager_cache = [];
|
||||
|
||||
if($ldap_default_group != null) {
|
||||
|
@ -229,7 +225,7 @@ class LdapSync extends Command
|
|||
} else {
|
||||
// Creating a new user.
|
||||
$user = new User;
|
||||
$user->password = $pass;
|
||||
$user->password = $user->noPassword();
|
||||
$user->activated = 1; // newly created users can log in by default, unless AD's UAC is in use, or an active flag is set (below)
|
||||
$item['createorupdate'] = 'created';
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ class AssetModelsController extends Controller
|
|||
'requestable',
|
||||
'assets_count',
|
||||
'category',
|
||||
'fieldset',
|
||||
];
|
||||
|
||||
$assetmodels = AssetModel::select([
|
||||
|
@ -94,6 +95,9 @@ class AssetModelsController extends Controller
|
|||
case 'category':
|
||||
$assetmodels->OrderCategory($order);
|
||||
break;
|
||||
case 'fieldset':
|
||||
$assetmodels->OrderFieldset($order);
|
||||
break;
|
||||
default:
|
||||
$assetmodels->orderBy($sort, $order);
|
||||
break;
|
||||
|
|
|
@ -27,7 +27,7 @@ class DepartmentsController extends Controller
|
|||
$this->authorize('view', Department::class);
|
||||
$allowed_columns = ['id', 'name', 'image', 'users_count'];
|
||||
|
||||
$departments = Company::scopeCompanyables(Department::select(
|
||||
$departments = Department::select(
|
||||
'departments.id',
|
||||
'departments.name',
|
||||
'departments.phone',
|
||||
|
@ -37,8 +37,8 @@ class DepartmentsController extends Controller
|
|||
'departments.manager_id',
|
||||
'departments.created_at',
|
||||
'departments.updated_at',
|
||||
'departments.image'),
|
||||
"company_id", "departments")->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
|
||||
'departments.image'
|
||||
)->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$departments = $departments->TextSearch($request->input('search'));
|
||||
|
|
|
@ -363,8 +363,12 @@ class UsersController extends Controller
|
|||
$user->permissions = $permissions_array;
|
||||
}
|
||||
|
||||
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40);
|
||||
$user->password = bcrypt($request->get('password', $tmp_pass));
|
||||
//
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->get('password'));
|
||||
} else {
|
||||
$user->password = $user->noPassword();
|
||||
}
|
||||
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use App\Helpers\Helper;
|
|||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\AssetModel;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
@ -174,7 +175,14 @@ class AssetModelsController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($model->save()) {
|
||||
if ($model->wasChanged('eol')) {
|
||||
$newEol = $model->eol;
|
||||
$model->assets()->whereNotNull('purchase_date')->where('eol_explicit', false)
|
||||
->update(['asset_eol_date' => DB::raw('DATE_ADD(purchase_date, INTERVAL ' . $newEol . ' MONTH)')]);
|
||||
}
|
||||
return redirect()->route('models.index')->with('success', trans('admin/models/message.update.success'));
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,8 @@ class AssetCheckoutController extends Controller
|
|||
|
||||
$settings = \App\Models\Setting::getSettings();
|
||||
|
||||
if ($settings->full_multiple_companies_support){
|
||||
// We have to check whether $target->company_id is null here since locations don't have a company yet
|
||||
if (($settings->full_multiple_companies_support) && ((!is_null($target->company_id)) && (!is_null($asset->company_id)))) {
|
||||
if ($target->company_id != $asset->company_id){
|
||||
return redirect()->to("hardware/$assetId/checkout")->with('error', trans('general.error_user_company'));
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use App\Helpers\Helper;
|
|||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Actionlog;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CheckoutRequest;
|
||||
|
@ -14,26 +15,18 @@ use App\Models\Location;
|
|||
use App\Models\Setting;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\View\Label;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
use Input;
|
||||
use Intervention\Image\Facades\Image;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use League\Csv\Reader;
|
||||
use League\Csv\Statement;
|
||||
use Paginator;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use Slack;
|
||||
use Str;
|
||||
use TCPDF;
|
||||
use View;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
|
||||
/**
|
||||
* This class controls all actions related to assets for
|
||||
|
@ -173,9 +166,9 @@ class AssetsController extends Controller
|
|||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = \Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -298,10 +291,10 @@ class AssetsController extends Controller
|
|||
/**
|
||||
* Validate and process asset edit form.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $assetId
|
||||
* @since [v1.0]
|
||||
* @return Redirect
|
||||
* @return \Illuminate\Http\RedirectResponse|Redirect
|
||||
*@since [v1.0]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public function update(ImageUploadRequest $request, $assetId = null)
|
||||
{
|
||||
|
@ -315,9 +308,23 @@ class AssetsController extends Controller
|
|||
$asset->status_id = $request->input('status_id', null);
|
||||
$asset->warranty_months = $request->input('warranty_months', null);
|
||||
$asset->purchase_cost = $request->input('purchase_cost', null);
|
||||
$asset->asset_eol_date = request('asset_eol_date', null);
|
||||
|
||||
$asset->purchase_date = $request->input('purchase_date', null);
|
||||
if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && $asset->model->eol) {
|
||||
$asset->purchase_date = $request->input('purchase_date', null);
|
||||
$asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
} elseif ($request->filled('asset_eol_date')) {
|
||||
$asset->asset_eol_date = $request->input('asset_eol_date', null);
|
||||
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
|
||||
if($asset->model->eol) {
|
||||
if($months != $asset->model->eol) {
|
||||
$asset->eol_explicit = true;
|
||||
} else {
|
||||
$asset->eol_explicit = false;
|
||||
}
|
||||
} else {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
}
|
||||
$asset->supplier_id = $request->input('supplier_id', null);
|
||||
$asset->expected_checkin = $request->input('expected_checkin', null);
|
||||
|
||||
|
@ -342,7 +349,7 @@ class AssetsController extends Controller
|
|||
unlink(public_path().'/uploads/assets/'.$asset->image);
|
||||
$asset->image = '';
|
||||
} catch (\Exception $e) {
|
||||
\Log::info($e);
|
||||
Log::info($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,9 +377,9 @@ class AssetsController extends Controller
|
|||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = \Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = \Crypt::encrypt($request->input($field->db_column));
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -420,7 +427,7 @@ class AssetsController extends Controller
|
|||
try {
|
||||
Storage::disk('public')->delete('assets'.'/'.$asset->image);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,7 +542,7 @@ class AssetsController extends Controller
|
|||
|
||||
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug('The barcode format is invalid.');
|
||||
Log::debug('The barcode format is invalid.');
|
||||
|
||||
return response(file_get_contents(public_path('uploads/barcodes/invalid_barcode.gif')))->header('Content-type', 'image/gif');
|
||||
}
|
||||
|
@ -856,7 +863,7 @@ class AssetsController extends Controller
|
|||
'next_audit_date' => 'date|nullable',
|
||||
];
|
||||
|
||||
$validator = \Validator::make($request->all(), $rules);
|
||||
$validator = Validator::make($request->all(), $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
|
||||
|
@ -873,7 +880,7 @@ class AssetsController extends Controller
|
|||
// Check to see if they checked the box to update the physical location,
|
||||
// not just note it in the audit notes
|
||||
if ($request->input('update_location') == '1') {
|
||||
\Log::debug('update location in audit');
|
||||
Log::debug('update location in audit');
|
||||
$asset->location_id = $request->input('location_id');
|
||||
}
|
||||
|
||||
|
|
|
@ -191,9 +191,11 @@ class LoginController extends Controller
|
|||
|
||||
$ldap_attr = Ldap::parseAndMapLdapAttributes($ldap_user);
|
||||
|
||||
$user->password = $user->noPassword();
|
||||
if (Setting::getSettings()->ldap_pw_sync=='1') {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
|
||||
$user->email = $ldap_attr['email'];
|
||||
$user->first_name = $ldap_attr['firstname'];
|
||||
$user->last_name = $ldap_attr['lastname']; //FIXME (or TODO?) - do we need to map additional fields that we now support? E.g. country, phone, etc.
|
||||
|
|
|
@ -31,7 +31,7 @@ class LabelsController extends Controller
|
|||
|
||||
$exampleAsset->id = 999999;
|
||||
$exampleAsset->name = 'JEN-867-5309';
|
||||
$exampleAsset->asset_tag = 'TCA-00001';
|
||||
$exampleAsset->asset_tag = '100001';
|
||||
$exampleAsset->serial = 'SN9876543210';
|
||||
|
||||
$exampleAsset->company = new Company();
|
||||
|
|
|
@ -76,7 +76,7 @@ class LicenseCheckinController extends Controller
|
|||
|
||||
// Declare the rules for the form validation
|
||||
$rules = [
|
||||
'note' => 'string|nullable',
|
||||
'notes' => 'string|nullable',
|
||||
];
|
||||
|
||||
// Create a new validator instance from our validation rules
|
||||
|
@ -97,6 +97,7 @@ class LicenseCheckinController extends Controller
|
|||
// Update the asset data
|
||||
$licenseSeat->assigned_to = null;
|
||||
$licenseSeat->asset_id = null;
|
||||
$licenseSeat->notes = $request->input('notes');
|
||||
|
||||
// Was the asset updated?
|
||||
if ($licenseSeat->save()) {
|
||||
|
@ -128,6 +129,13 @@ class LicenseCheckinController extends Controller
|
|||
$license = License::findOrFail($licenseId);
|
||||
$this->authorize('checkin', $license);
|
||||
|
||||
if (! $license->reassignable) {
|
||||
// Not allowed to checkin
|
||||
Session::flash('error', 'License not reassignable.');
|
||||
|
||||
return redirect()->back()->withInput();
|
||||
}
|
||||
|
||||
$licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId)
|
||||
->whereNotNull('assigned_to')
|
||||
->with('user')
|
||||
|
|
|
@ -63,6 +63,7 @@ class LicenseCheckoutController extends Controller
|
|||
|
||||
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
|
||||
$licenseSeat->user_id = Auth::id();
|
||||
$licenseSeat->notes = $request->input('notes');
|
||||
|
||||
|
||||
$checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type'));
|
||||
|
|
|
@ -275,6 +275,7 @@ class Importer extends Component
|
|||
'license_email' => trans('admin/licenses/form.to_email'),
|
||||
'license_name' => trans('admin/licenses/form.to_name'),
|
||||
'purchase_order' => trans('admin/licenses/form.purchase_order'),
|
||||
'order_number' => trans('general.order_number'),
|
||||
'reassignable' => trans('admin/licenses/form.reassignable'),
|
||||
'seats' => trans('admin/licenses/form.seats'),
|
||||
'notes' => trans('general.notes'),
|
||||
|
@ -484,8 +485,17 @@ class Importer extends Component
|
|||
|
||||
public function selectFile($id)
|
||||
{
|
||||
$this->clearMessage();
|
||||
|
||||
$this->activeFile = Import::find($id);
|
||||
|
||||
if (!$this->activeFile) {
|
||||
$this->message = trans('admin/hardware/message.import.file_missing');
|
||||
$this->message_type = 'danger';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->field_map = null;
|
||||
foreach($this->activeFile->header_row as $element) {
|
||||
if(isset($this->activeFile->field_map[$element])) {
|
||||
|
@ -520,6 +530,12 @@ class Importer extends Component
|
|||
}
|
||||
}
|
||||
|
||||
public function clearMessage()
|
||||
{
|
||||
$this->message = null;
|
||||
$this->message_type = null;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$this->files = Import::orderBy('id','desc')->get(); //HACK - slows down renders.
|
||||
|
|
|
@ -12,7 +12,7 @@ class SlackSettingsForm extends Component
|
|||
public $webhook_endpoint;
|
||||
public $webhook_channel;
|
||||
public $webhook_botname;
|
||||
public $isDisabled ='' ;
|
||||
public $isDisabled ='disabled' ;
|
||||
public $webhook_name;
|
||||
public $webhook_link;
|
||||
public $webhook_placeholder;
|
||||
|
@ -22,11 +22,17 @@ class SlackSettingsForm extends Component
|
|||
|
||||
public Setting $setting;
|
||||
|
||||
public $webhook_endpoint_rules;
|
||||
|
||||
|
||||
protected $rules = [
|
||||
'webhook_endpoint' => 'url|required_with:webhook_channel|starts_with:https://hooks.slack.com/services|nullable',
|
||||
'webhook_endpoint' => 'required_with:webhook_channel|starts_with:http://,https://,ftp://,irc://,https://hooks.slack.com/services/|url|nullable',
|
||||
'webhook_channel' => 'required_with:webhook_endpoint|starts_with:#|nullable',
|
||||
'webhook_botname' => 'string|nullable',
|
||||
];
|
||||
public $messages = [
|
||||
'webhook_endpoint.starts_with' => 'your webhook endpoint should begin with http://, https:// or other protocol.',
|
||||
];
|
||||
|
||||
public function mount() {
|
||||
$this->webhook_text= [
|
||||
|
@ -55,9 +61,7 @@ class SlackSettingsForm extends Component
|
|||
$this->webhook_botname = $this->setting->webhook_botname;
|
||||
$this->webhook_options = $this->setting->webhook_selected;
|
||||
|
||||
if($this->setting->webhook_selected == 'general'){
|
||||
$this->isDisabled='';
|
||||
}
|
||||
|
||||
if($this->setting->webhook_endpoint != null && $this->setting->webhook_channel != null){
|
||||
$this->isDisabled= '';
|
||||
}
|
||||
|
@ -65,9 +69,8 @@ class SlackSettingsForm extends Component
|
|||
}
|
||||
public function updated($field) {
|
||||
|
||||
if($this->webhook_selected != 'general') {
|
||||
$this->validateOnly($field, $this->rules);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function updatedWebhookSelected() {
|
||||
|
@ -82,7 +85,6 @@ class SlackSettingsForm extends Component
|
|||
}
|
||||
|
||||
private function isButtonDisabled() {
|
||||
if($this->webhook_selected == 'slack') {
|
||||
if (empty($this->webhook_endpoint)) {
|
||||
$this->isDisabled = 'disabled';
|
||||
$this->save_button = trans('admin/settings/general.webhook_presave');
|
||||
|
@ -93,8 +95,6 @@ class SlackSettingsForm extends Component
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$this->isButtonDisabled();
|
||||
|
@ -108,6 +108,7 @@ class SlackSettingsForm extends Component
|
|||
'defaults' => [
|
||||
'exceptions' => false,
|
||||
],
|
||||
'allow_redirects' => false,
|
||||
]);
|
||||
|
||||
$payload = json_encode(
|
||||
|
@ -116,18 +117,23 @@ class SlackSettingsForm extends Component
|
|||
'text' => trans('general.webhook_test_msg', ['app' => $this->webhook_name]),
|
||||
'username' => e($this->webhook_botname),
|
||||
'icon_emoji' => ':heart:',
|
||||
|
||||
]);
|
||||
|
||||
try {
|
||||
$test = $webhook->post($this->webhook_endpoint, ['body' => $payload]);
|
||||
|
||||
$webhook->post($this->webhook_endpoint, ['body' => $payload]);
|
||||
if(($test->getStatusCode() == 302)||($test->getStatusCode() == 301)){
|
||||
return session()->flash('error' , trans('admin/settings/message.webhook.error_redirect', ['endpoint' => $this->webhook_endpoint]));
|
||||
}
|
||||
$this->isDisabled='';
|
||||
$this->save_button = trans('general.save');
|
||||
return session()->flash('success' , 'Your '.$this->webhook_name.' Integration works!');
|
||||
return session()->flash('success' , trans('admin/settings/message.webhook.success', ['webhook_name' => $this->webhook_name]));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->isDisabled= 'disabled';
|
||||
$this->isDisabled='disabled';
|
||||
$this->save_button = trans('admin/settings/general.webhook_presave');
|
||||
return session()->flash('error' , trans('admin/settings/message.webhook.error', ['error_message' => $e->getMessage(), 'app' => $this->webhook_name]));
|
||||
}
|
||||
|
||||
|
@ -158,9 +164,7 @@ class SlackSettingsForm extends Component
|
|||
if (Helper::isDemoMode()) {
|
||||
session()->flash('error',trans('general.feature_disabled'));
|
||||
} else {
|
||||
if ($this->webhook_selected != 'general') {
|
||||
$this->validate($this->rules);
|
||||
}
|
||||
|
||||
$this->setting->webhook_selected = $this->webhook_selected;
|
||||
$this->setting->webhook_endpoint = $this->webhook_endpoint;
|
||||
|
|
|
@ -43,9 +43,10 @@ class ActionlogsTransformer
|
|||
public function transformActionlog (Actionlog $actionlog, $settings = null)
|
||||
{
|
||||
$icon = $actionlog->present()->icon();
|
||||
$custom_field = CustomField::all();
|
||||
$custom_fields = CustomField::all();
|
||||
|
||||
if ($actionlog->filename!='') {
|
||||
$icon = e(\App\Helpers\Helper::filetype_icon($actionlog->filename));
|
||||
$icon = Helper::filetype_icon($actionlog->filename);
|
||||
}
|
||||
|
||||
// This is necessary since we can't escape special characters within a JSON object
|
||||
|
@ -55,17 +56,29 @@ class ActionlogsTransformer
|
|||
$clean_meta = [];
|
||||
|
||||
if ($meta_array) {
|
||||
|
||||
foreach ($meta_array as $fieldname => $fieldata) {
|
||||
if( str_starts_with($fieldname, '_snipeit_')){
|
||||
if( $custom_field->where('db_column', '=', $fieldname)->where('field_encrypted', true)){
|
||||
$clean_meta[$fieldname]['old'] = "encrypted";
|
||||
$clean_meta[$fieldname]['new'] = "encrypted";
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
$clean_meta[$fieldname]['old'] = $this->clean_field($fieldata->old);
|
||||
$clean_meta[$fieldname]['new'] = $this->clean_field($fieldata->new);
|
||||
|
||||
// this is a custom field
|
||||
if (str_starts_with($fieldname, '_snipeit_')) {
|
||||
|
||||
foreach ($custom_fields as $custom_field) {
|
||||
|
||||
if ($custom_field->db_column == $fieldname) {
|
||||
|
||||
if ($custom_field->field_encrypted == '1') {
|
||||
$clean_meta[$fieldname]['old'] = "************";
|
||||
$clean_meta[$fieldname]['new'] = "************";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ class LicenseSeatsTransformer
|
|||
'name'=> e($seat->location()->name),
|
||||
] : null,
|
||||
'reassignable' => (bool) $seat->license->reassignable,
|
||||
'notes' => e($seat->notes),
|
||||
'user_can_checkout' => (($seat->assigned_to == '') && ($seat->asset_id == '')),
|
||||
];
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
namespace App\Importer;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Statuslabel;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AssetImporter extends ItemImporter
|
||||
{
|
||||
|
@ -63,6 +65,7 @@ class AssetImporter extends ItemImporter
|
|||
$asset_tag = Asset::autoincrement_asset();
|
||||
}
|
||||
|
||||
|
||||
$asset = Asset::where(['asset_tag'=> (string) $asset_tag])->first();
|
||||
if ($asset) {
|
||||
if (! $this->updating) {
|
||||
|
@ -117,11 +120,6 @@ class AssetImporter extends ItemImporter
|
|||
$item['next_audit_date'] = $this->item['next_audit_date'];
|
||||
}
|
||||
|
||||
$item['asset_eol_date'] = null;
|
||||
if (isset($this->item['asset_eol_date'])) {
|
||||
$item['asset_eol_date'] = $this->item['asset_eol_date'];
|
||||
}
|
||||
|
||||
if ($editingAsset) {
|
||||
$asset->update($item);
|
||||
} else {
|
||||
|
@ -135,8 +133,8 @@ class AssetImporter extends ItemImporter
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if ($asset->save()) {
|
||||
|
||||
$asset->logCreate(trans('general.importer.import_note'));
|
||||
$this->log('Asset '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ abstract class Importer
|
|||
/**
|
||||
* Default Map of item fields->csv names
|
||||
*
|
||||
* This has been moved into Livewire/Importer.php to be more granular.
|
||||
* This has been moved into app/Http/Livewire/Importer.php to be more granular.
|
||||
* @todo - remove references to this property since we don't use it anymore.
|
||||
*
|
||||
* @var array
|
||||
|
|
|
@ -10,6 +10,8 @@ use App\Models\Manufacturer;
|
|||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ItemImporter extends Importer
|
||||
{
|
||||
|
@ -88,8 +90,14 @@ class ItemImporter extends Importer
|
|||
}
|
||||
|
||||
$this->item['asset_eol_date'] = null;
|
||||
if ($this->findCsvMatch($row, 'asset_eol_date') != '') {
|
||||
$this->item['asset_eol_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'asset_eol_date')));
|
||||
if($this->findCsvMatch($row, 'asset_eol_date') != '') {
|
||||
$csvMatch = $this->findCsvMatch($row, 'asset_eol_date');
|
||||
try {
|
||||
$this->item['asset_eol_date'] = CarbonImmutable::parse($csvMatch)->format('Y-m-d');
|
||||
} catch (\Exception $e) {
|
||||
Log::info($e->getMessage());
|
||||
$this->log('Unable to parse date: '.$csvMatch);
|
||||
}
|
||||
}
|
||||
|
||||
$this->item['qty'] = $this->findCsvMatch($row, 'quantity');
|
||||
|
|
|
@ -65,6 +65,7 @@ class LicenseImporter extends ItemImporter
|
|||
$this->item['license_name'] = $this->findCsvMatch($row, 'license_name');
|
||||
$this->item['maintained'] = $this->findCsvMatch($row, 'maintained');
|
||||
$this->item['purchase_order'] = $this->findCsvMatch($row, 'purchase_order');
|
||||
$this->item['order_number'] = $this->findCsvMatch($row, 'order_number');
|
||||
$this->item['reassignable'] = $this->findCsvMatch($row, 'reassignable');
|
||||
$this->item['manufacturer'] = $this->createOrFetchManufacturer($this->findCsvMatch($row, 'manufacturer'));
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ class CheckoutableListener
|
|||
/**
|
||||
* Send the appropriate notification
|
||||
*/
|
||||
if ($event->checkedOutTo && $event->checkoutable){
|
||||
$acceptances = CheckoutAcceptance::where('checkoutable_id', $event->checkoutable->id)
|
||||
->where('assigned_to_id', $event->checkedOutTo->id)
|
||||
->get();
|
||||
|
@ -88,6 +89,7 @@ class CheckoutableListener
|
|||
$acceptance->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->shouldSendWebhookNotification()) {
|
||||
|
@ -142,9 +144,11 @@ class CheckoutableListener
|
|||
$notifiables = collect();
|
||||
|
||||
/**
|
||||
* Notify the user who checked out the item
|
||||
* Notify who checked out the item as long as the model can route notifications
|
||||
*/
|
||||
if (method_exists($event->checkedOutTo, 'routeNotificationFor')) {
|
||||
$notifiables->push($event->checkedOutTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify Admin users if the settings is activated
|
||||
|
|
|
@ -72,6 +72,8 @@ class Asset extends Depreciable
|
|||
|
||||
protected $casts = [
|
||||
'purchase_date' => 'date',
|
||||
'asset_eol_date' => 'date',
|
||||
'eol_explicit' => 'boolean',
|
||||
'last_checkout' => 'datetime',
|
||||
'last_checkin' => 'datetime',
|
||||
'expected_checkin' => 'date',
|
||||
|
@ -104,7 +106,8 @@ class Asset extends Depreciable
|
|||
'serial' => 'unique_serial|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0',
|
||||
'supplier_id' => 'exists:suppliers,id|nullable',
|
||||
'asset_eol_date' => 'date|max:10|min:10|nullable',
|
||||
'asset_eol_date' => 'date|nullable',
|
||||
'eol_explicit' => 'boolean|nullable',
|
||||
'byod' => 'boolean',
|
||||
];
|
||||
|
||||
|
@ -136,8 +139,10 @@ class Asset extends Depreciable
|
|||
'expected_checkin',
|
||||
'byod',
|
||||
'asset_eol_date',
|
||||
'eol_explicit',
|
||||
'last_audit_date',
|
||||
'next_audit_date',
|
||||
'asset_eol_date',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
|
|
|
@ -291,4 +291,9 @@ class AssetModel extends SnipeModel
|
|||
{
|
||||
return $query->leftJoin('categories', 'models.category_id', '=', 'categories.id')->orderBy('categories.name', $order);
|
||||
}
|
||||
|
||||
public function scopeOrderFieldset($query, $order)
|
||||
{
|
||||
return $query->leftJoin('custom_fieldsets', 'models.fieldset_id', '=', 'custom_fieldsets.id')->orderBy('custom_fieldsets.name', $order);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use Watson\Validating\ValidatingTrait;
|
|||
|
||||
class Department extends SnipeModel
|
||||
{
|
||||
use CompanyableTrait;
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,8 @@ class Field {
|
|||
|
||||
public static function makeArray(Field $field, Asset $asset) {
|
||||
return $field->getOptions()
|
||||
// filter out any FieldOptions that are accidentally null
|
||||
->filter()
|
||||
->map(fn($option) => $option->toArray($asset))
|
||||
->filter(fn($result) => $result['value'] != null);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use Illuminate\Support\Collection;
|
|||
use Illuminate\Support\Facades\File;
|
||||
use TCPDF;
|
||||
use TCPDF_STATIC;
|
||||
use TypeError;
|
||||
|
||||
/**
|
||||
* Model for Labels.
|
||||
|
@ -372,8 +373,8 @@ abstract class Label
|
|||
if (empty($value)) return;
|
||||
try {
|
||||
$pdf->write1DBarcode($value, $type, $x, $y, $width, $height, null, ['stretch'=>true]);
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('The 1D barcode ' . $value . ' is not compliant with the barcode type '. $type);
|
||||
} catch (\Exception|TypeError $e) {
|
||||
\Log::debug('The 1D barcode ' . $value . ' is not compliant with the barcode type '. $type);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -252,13 +252,10 @@ class Ldap extends Model
|
|||
$user->last_name = $item['lastname'];
|
||||
$user->username = $item['username'];
|
||||
$user->email = $item['email'];
|
||||
$user->password = $user->noPassword();
|
||||
|
||||
if (Setting::getSettings()->ldap_pw_sync == '1') {
|
||||
|
||||
$user->password = bcrypt($password);
|
||||
} else {
|
||||
$pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 25);
|
||||
$user->password = bcrypt($pass);
|
||||
}
|
||||
|
||||
$user->activated = 1;
|
||||
|
@ -268,7 +265,7 @@ class Ldap extends Model
|
|||
if ($user->save()) {
|
||||
return $user;
|
||||
} else {
|
||||
LOG::debug('Could not create user.'.$user->getErrors());
|
||||
\Log::debug('Could not create user.'.$user->getErrors());
|
||||
throw new Exception('Could not create user: '.$user->getErrors());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@ class SCIMUser extends User
|
|||
protected $throwValidationExceptions = true; // we want model-level validation to fully THROW, not just return false
|
||||
|
||||
public function __construct(array $attributes = []) {
|
||||
$attributes['password'] = "*NO PASSWORD*";
|
||||
// $attributes['activated'] = 1;
|
||||
$attributes['password'] = $this->noPassword();
|
||||
parent::__construct($attributes);
|
||||
}
|
||||
}
|
|
@ -456,6 +456,22 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
return $this->belongsToMany(Asset::class, 'checkout_requests', 'user_id', 'requestable_id')->whereNull('canceled_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a common string when the user has been imported/synced from:
|
||||
*
|
||||
* - LDAP without password syncing
|
||||
* - SCIM
|
||||
* - CSV import where no password was provided
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v6.2.0]
|
||||
* @return string
|
||||
*/
|
||||
public function noPassword()
|
||||
{
|
||||
return "*** NO PASSWORD ***";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query builder scope to return NOT-deleted users
|
||||
|
|
|
@ -6,6 +6,7 @@ use App\Models\Actionlog;
|
|||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AssetObserver
|
||||
{
|
||||
|
@ -119,4 +120,29 @@ class AssetObserver
|
|||
$logAction->user_id = Auth::id();
|
||||
$logAction->logaction('delete');
|
||||
}
|
||||
|
||||
public function saving(Asset $asset)
|
||||
{
|
||||
//determine if calculated eol and then calculate it - this should only happen on a new asset
|
||||
if(is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && !is_null($asset->model->eol)){
|
||||
$asset->asset_eol_date = $asset->purchase_date->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
$asset->eol_explicit = false;
|
||||
}
|
||||
|
||||
//determine if explicit and set eol_explit to true
|
||||
if(!is_null($asset->asset_eol_date) && !is_null($asset->purchase_date)) {
|
||||
if($asset->model->eol) {
|
||||
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
|
||||
if($months != $asset->model->eol) {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
}
|
||||
} elseif (!is_null($asset->asset_eol_date) && is_null($asset->purchase_date)) {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
if ((!is_null($asset->asset_eol_date)) && (!is_null($asset->purchase_date)) && (is_null($asset->model->eol))) {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Presenters;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use Carbon\CarbonImmutable;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
|
@ -142,8 +143,8 @@ class AssetPresenter extends Presenter
|
|||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'age',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'visible' => false,
|
||||
'title' => trans('general.age'),
|
||||
], [
|
||||
|
@ -429,10 +430,7 @@ class AssetPresenter extends Presenter
|
|||
public function eol_date()
|
||||
{
|
||||
if (($this->purchase_date) && ($this->model->model) && ($this->model->model->eol)) {
|
||||
$date = date_create($this->purchase_date);
|
||||
date_add($date, date_interval_create_from_date_string($this->model->model->eol.' months'));
|
||||
|
||||
return date_format($date, 'Y-m-d');
|
||||
return CarbonImmutable::parse($this->purchase_date)->addMonths($this->model->model->eol)->format('Y-m-d');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -254,6 +254,14 @@ class LicensePresenter extends Presenter
|
|||
'visible' => true,
|
||||
'formatter' => 'locationsLinkObjFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'notes',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'visible' => false,
|
||||
'title' => trans('general.notes'),
|
||||
'formatter' => 'notesFormatter'
|
||||
],
|
||||
[
|
||||
'field' => 'checkincheckout',
|
||||
'searchable' => false,
|
||||
|
|
|
@ -239,7 +239,7 @@ return [
|
|||
|
|
||||
*/
|
||||
|
||||
'min_php' => '7.2.5',
|
||||
'min_php' => '7.4.0',
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -35,6 +35,13 @@ return [
|
|||
|
||||
'files' => [
|
||||
|
||||
/*
|
||||
* This path is used to make directories in resulting zip-file relative
|
||||
* Set to false to include complete absolute path
|
||||
* Example: base_path()
|
||||
*/
|
||||
'relative_path' => base_path(),
|
||||
|
||||
/*
|
||||
* The list of directories and files that will be included in the backup.
|
||||
*/
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
return array (
|
||||
'app_version' => 'v6.2.0-pre',
|
||||
'full_app_version' => 'v6.2.0-pre - build 11391-g319cb2305',
|
||||
'build_version' => '11391',
|
||||
'app_version' => 'v6.2.1',
|
||||
'full_app_version' => 'v6.2.1 - build 11625-gc45ede2d1',
|
||||
'build_version' => '11625',
|
||||
'prerelease_version' => '',
|
||||
'hash_version' => 'g319cb2305',
|
||||
'full_hash' => 'v6.2.0-pre-451-g319cb2305',
|
||||
'hash_version' => 'gc45ede2d1',
|
||||
'full_hash' => 'v6.2.1-47-gc45ede2d1',
|
||||
'branch' => 'develop',
|
||||
);
|
|
@ -8,6 +8,8 @@ use App\Models\Location;
|
|||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class AssetFactory extends Factory
|
||||
|
@ -49,6 +51,18 @@ class AssetFactory extends Factory
|
|||
];
|
||||
}
|
||||
|
||||
|
||||
public function configure()
|
||||
{
|
||||
return $this->afterMaking(function (Asset $asset) {
|
||||
// calculates the EOL date most of the time, but sometimes sets a random date so we have some explicits
|
||||
// the explicit boolean gets set in the saving() method on the observer
|
||||
$asset->asset_eol_date = $this->faker->boolean(5)
|
||||
? CarbonImmutable::parse($asset->purchase_date)->addMonths(rand(0, 20))->format('Y-m-d')
|
||||
: CarbonImmutable::parse($asset->purchase_date)->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
});
|
||||
}
|
||||
|
||||
public function laptopMbp()
|
||||
{
|
||||
return $this->state(function () {
|
||||
|
|
|
@ -22,7 +22,7 @@ class CompanyFactory extends Factory
|
|||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->company(),
|
||||
'name' => $this->faker->unique()->company(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class CustomFieldFactory extends Factory
|
|||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->catchPhrase(),
|
||||
'name' => $this->faker->unique()->catchPhrase(),
|
||||
'format' => '',
|
||||
'element' => 'text',
|
||||
'auto_add_to_fieldsets' => '0',
|
||||
|
|
|
@ -22,7 +22,7 @@ class CustomFieldsetFactory extends Factory
|
|||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->catchPhrase(),
|
||||
'name' => $this->faker->unique()->catchPhrase(),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class DepreciationFactory extends Factory
|
|||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->catchPhrase(),
|
||||
'name' => $this->faker->unique()->catchPhrase(),
|
||||
'user_id' => User::factory()->superuser(),
|
||||
'months' => 36,
|
||||
];
|
||||
|
|
|
@ -23,7 +23,7 @@ class ManufacturerFactory extends Factory
|
|||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->company(),
|
||||
'name' => $this->faker->unique()->company(),
|
||||
'user_id' => User::factory()->superuser(),
|
||||
'support_phone' => $this->faker->phoneNumber(),
|
||||
'url' => $this->faker->url(),
|
||||
|
|
|
@ -33,7 +33,7 @@ class UserFactory extends Factory
|
|||
'permissions' => '{}',
|
||||
'phone' => $this->faker->phoneNumber(),
|
||||
'state' => $this->faker->stateAbbr(),
|
||||
'username' => $this->faker->username(),
|
||||
'username' => $this->faker->unique()->username(),
|
||||
'zip' => $this->faker->postcode(),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Asset;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DenormalizedEolAndAddColumnForExplicitDateToAssets extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('assets', function (Blueprint $table) {
|
||||
$table->boolean('eol_explicit')->default(false)->after('asset_eol_date');
|
||||
});
|
||||
|
||||
|
||||
// Update the eol_explicit column with the value from asset_eol_date if it exists and is different from the calculated value
|
||||
Asset::whereNotNull('asset_eol_date')->with('model')->chunkById(500, function ($assetsWithEolDates) {
|
||||
foreach ($assetsWithEolDates as $asset) {
|
||||
if ($asset->asset_eol_date && $asset->purchase_date) {
|
||||
try {
|
||||
$months = CarbonImmutable::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
|
||||
} catch (\Exception $e) {
|
||||
Log::info('asset_eol_date invalid for asset '.$asset->id);
|
||||
}
|
||||
if ($asset->model->eol) {
|
||||
if ($months != $asset->model->eol) {
|
||||
$asset->update(['eol_explicit' => true]);
|
||||
}
|
||||
} else {
|
||||
$asset->update(['eol_explicit' => true]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update the asset_eol_date column with the calculated value if it doesn't exist
|
||||
Asset::whereNull('asset_eol_date')->with('model')->chunkById(500, function ($assets) {
|
||||
foreach ($assets as $asset) {
|
||||
if ($asset->model->eol && $asset->purchase_date) {
|
||||
try {
|
||||
$asset_eol_date = CarbonImmutable::parse($asset->purchase_date)->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
$asset->update(['asset_eol_date' => $asset_eol_date]);
|
||||
} catch (\Exception $e) {
|
||||
Log::info('purchase date invalid for asset '.$asset->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('assets', function (Blueprint $table) {
|
||||
$table->dropColumn('eol_explicit');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class FixAssetModelMinQtyNullability extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('models', function (Blueprint $table) {
|
||||
$table->integer('min_amt')->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('models', function (Blueprint $table) {
|
||||
$table->integer('min_amt')->nullable(false)->change();
|
||||
});
|
||||
}
|
||||
}
|
3781
package-lock.json
generated
3781
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -37,6 +37,7 @@
|
|||
"bootstrap-less": "^3.3.8",
|
||||
"bootstrap-table": "1.22.1",
|
||||
"chart.js": "^2.9.4",
|
||||
"clipboard": "^2.0.11",
|
||||
"css-loader": "^4.0.0",
|
||||
"ekko-lightbox": "^5.1.1",
|
||||
"imagemin": "^8.0.1",
|
||||
|
|
Binary file not shown.
Binary file not shown.
BIN
public/css/dist/all.css
vendored
BIN
public/css/dist/all.css
vendored
Binary file not shown.
BIN
public/css/dist/bootstrap-table.css
vendored
BIN
public/css/dist/bootstrap-table.css
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/js/dist/all-defer.js
vendored
BIN
public/js/dist/all-defer.js
vendored
Binary file not shown.
BIN
public/js/dist/all.js
vendored
BIN
public/js/dist/all.js
vendored
Binary file not shown.
BIN
public/js/dist/bootstrap-table.js
vendored
BIN
public/js/dist/bootstrap-table.js
vendored
Binary file not shown.
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"/js/build/app.js": "/js/build/app.js?id=43fc984e5d0f901e04cef2474972e97f",
|
||||
"/js/build/app.js": "/js/build/app.js?id=72071a8a4dc754c61b0440d3c4119cbf",
|
||||
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=392cc93cfc0be0349bab9697669dd091",
|
||||
"/css/build/overrides.css": "/css/build/overrides.css?id=eb013ebb79d92e25ce24b0c0b53185e4",
|
||||
"/css/build/app.css": "/css/build/app.css?id=ac51a0600b419996e705675b6fcf1a8b",
|
||||
"/css/build/overrides.css": "/css/build/overrides.css?id=d96bcc45dc2a4414dd9840a14b096d4f",
|
||||
"/css/build/app.css": "/css/build/app.css?id=b0aa590a3a4de33d19147264fd31b743",
|
||||
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=a67bd93bed52e6a29967fe472de66d6c",
|
||||
"/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=829410b57e28448fef5c57beda0861e3",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=6d6bfa80b1bd2785b35a85ea81daafc8",
|
||||
"/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=a656b2d865fe379d8851757e8e4001ef",
|
||||
|
@ -29,10 +29,10 @@
|
|||
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=7f63d634454e771396bce3e09dfcdbc5",
|
||||
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=70ad875b2378eb850254f01dec991ade",
|
||||
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=d36941873b661076f146b0221f13497d",
|
||||
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=281bcfe26549412d128f695234961081",
|
||||
"/js/build/vendor.js": "/js/build/vendor.js?id=8ac1d250496313e93744790e5138305d",
|
||||
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=df78f0c4cc93c29c02a41144590f6350",
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=b487452bd6bef7fa6201586415d383f2",
|
||||
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=2bd29fa7f9d666800c246a52ce708633",
|
||||
"/js/build/vendor.js": "/js/build/vendor.js?id=ede02ee2aad89fe10c64a87f6c76838a",
|
||||
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=1f678160a05960c3087fb8263168ff41",
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=c539685e205ada5b7259499d491fae87",
|
||||
"/js/dist/all-defer.js": "/js/dist/all-defer.js?id=07e52318da2cdf3171c4d88113f25fb6",
|
||||
"/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=44f9320d0739f419c9246f7f39395b02",
|
||||
|
|
40
resources/assets/css/dragtable.css
Normal file
40
resources/assets/css/dragtable.css
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* dragtable
|
||||
*
|
||||
* @Version 2.0.15
|
||||
*
|
||||
* default css
|
||||
*
|
||||
*/
|
||||
/*##### the dragtable stuff #####*/
|
||||
.dragtable-sortable {
|
||||
list-style-type: none; margin: 0; padding: 0; -moz-user-select: none;
|
||||
}
|
||||
.dragtable-sortable li {
|
||||
margin: 0; padding: 0; float: left; font-size: 1em; background: white;
|
||||
}
|
||||
|
||||
.dragtable-sortable th, .dragtable-sortable td{
|
||||
border-left: 0px;
|
||||
}
|
||||
|
||||
.dragtable-sortable li:first-child th, .dragtable-sortable li:first-child td {
|
||||
border-left: 1px solid #CCC;
|
||||
}
|
||||
|
||||
.ui-sortable-helper {
|
||||
opacity: 0.7;filter: alpha(opacity=70);
|
||||
}
|
||||
.ui-sortable-placeholder {
|
||||
-moz-box-shadow: 4px 5px 4px #C6C6C6 inset;
|
||||
-webkit-box-shadow: 4px 5px 4px #C6C6C6 inset;
|
||||
box-shadow: 4px 5px 4px #C6C6C6 inset;
|
||||
border-bottom: 1px solid #CCCCCC;
|
||||
border-top: 1px solid #CCCCCC;
|
||||
visibility: visible !important;
|
||||
background: #EFEFEF !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
.ui-sortable-placeholder * {
|
||||
opacity: 0.0; visibility: hidden;
|
||||
}
|
2131
resources/assets/js/bootstrap-table-reorder-columns.js
vendored
Normal file
2131
resources/assets/js/bootstrap-table-reorder-columns.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
403
resources/assets/js/dragtable.js
Normal file
403
resources/assets/js/dragtable.js
Normal file
|
@ -0,0 +1,403 @@
|
|||
/*!
|
||||
* dragtable
|
||||
*
|
||||
* @Version 2.0.15
|
||||
*
|
||||
* Copyright (c) 2010-2013, Andres akottr@gmail.com
|
||||
* Dual licensed under the MIT (MIT-LICENSE.txt)
|
||||
* and GPL (GPL-LICENSE.txt) licenses.
|
||||
*
|
||||
* Inspired by the the dragtable from Dan Vanderkam (danvk.org/dragtable/)
|
||||
* Thanks to the jquery and jqueryui comitters
|
||||
*
|
||||
* Any comment, bug report, feature-request is welcome
|
||||
* Feel free to contact me.
|
||||
*/
|
||||
|
||||
/* TOKNOW:
|
||||
* For IE7 you need this css rule:
|
||||
* table {
|
||||
* border-collapse: collapse;
|
||||
* }
|
||||
* Or take a clean reset.css (see http://meyerweb.com/eric/tools/css/reset/)
|
||||
*/
|
||||
|
||||
/* TODO: investigate
|
||||
* Does not work properly with css rule:
|
||||
* html {
|
||||
* overflow: -moz-scrollbars-vertical;
|
||||
* }
|
||||
* Workaround:
|
||||
* Fixing Firefox issues by scrolling down the page
|
||||
* http://stackoverflow.com/questions/2451528/jquery-ui-sortable-scroll-helper-element-offset-firefox-issue
|
||||
*
|
||||
* var start = $.noop;
|
||||
* var beforeStop = $.noop;
|
||||
* if($.browser.mozilla) {
|
||||
* var start = function (event, ui) {
|
||||
* if( ui.helper !== undefined )
|
||||
* ui.helper.css('position','absolute').css('margin-top', $(window).scrollTop() );
|
||||
* }
|
||||
* var beforeStop = function (event, ui) {
|
||||
* if( ui.offset !== undefined )
|
||||
* ui.helper.css('margin-top', 0);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* and pass this as start and stop function to the sortable initialisation
|
||||
* start: start,
|
||||
* beforeStop: beforeStop
|
||||
*/
|
||||
/*
|
||||
* Special thx to all pull requests comitters
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$.widget("akottr.dragtable", {
|
||||
options: {
|
||||
revert: false, // smooth revert
|
||||
dragHandle: '.table-handle', // handle for moving cols, if not exists the whole 'th' is the handle
|
||||
maxMovingRows: 40, // 1 -> only header. 40 row should be enough, the rest is usually not in the viewport
|
||||
excludeFooter: false, // excludes the footer row(s) while moving other columns. Make sense if there is a footer with a colspan. */
|
||||
onlyHeaderThreshold: 100, // TODO: not implemented yet, switch automatically between entire col moving / only header moving
|
||||
dragaccept: null, // draggable cols -> default all
|
||||
persistState: null, // url or function -> plug in your custom persistState function right here. function call is persistState(originalTable)
|
||||
restoreState: null, // JSON-Object or function: some kind of experimental aka Quick-Hack TODO: do it better
|
||||
exact: true, // removes pixels, so that the overlay table width fits exactly the original table width
|
||||
clickDelay: 10, // ms to wait before rendering sortable list and delegating click event
|
||||
containment: null, // @see http://api.jqueryui.com/sortable/#option-containment, use it if you want to move in 2 dimesnions (together with axis: null)
|
||||
cursor: 'move', // @see http://api.jqueryui.com/sortable/#option-cursor
|
||||
cursorAt: false, // @see http://api.jqueryui.com/sortable/#option-cursorAt
|
||||
distance: 0, // @see http://api.jqueryui.com/sortable/#option-distance, for immediate feedback use "0"
|
||||
tolerance: 'pointer', // @see http://api.jqueryui.com/sortable/#option-tolerance
|
||||
axis: 'x', // @see http://api.jqueryui.com/sortable/#option-axis, Only vertical moving is allowed. Use 'x' or null. Use this in conjunction with the 'containment' setting
|
||||
beforeStart: $.noop, // returning FALSE will stop the execution chain.
|
||||
beforeMoving: $.noop,
|
||||
beforeReorganize: $.noop,
|
||||
beforeStop: $.noop
|
||||
},
|
||||
originalTable: {
|
||||
el: null,
|
||||
selectedHandle: null,
|
||||
sortOrder: null,
|
||||
startIndex: 0,
|
||||
endIndex: 0
|
||||
},
|
||||
sortableTable: {
|
||||
el: $(),
|
||||
selectedHandle: $(),
|
||||
movingRow: $()
|
||||
},
|
||||
persistState: function() {
|
||||
var _this = this;
|
||||
this.originalTable.el.find('th').each(function(i) {
|
||||
if (this.id !== '') {
|
||||
_this.originalTable.sortOrder[this.id] = i;
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
url: this.options.persistState,
|
||||
data: this.originalTable.sortOrder
|
||||
});
|
||||
},
|
||||
/*
|
||||
* persistObj looks like
|
||||
* {'id1':'2','id3':'3','id2':'1'}
|
||||
* table looks like
|
||||
* | id2 | id1 | id3 |
|
||||
*/
|
||||
_restoreState: function(persistObj) {
|
||||
for (var n in persistObj) {
|
||||
this.originalTable.startIndex = $('#' + n).closest('th').prevAll().length + 1;
|
||||
this.originalTable.endIndex = parseInt(persistObj[n], 10) + 1;
|
||||
this._bubbleCols();
|
||||
}
|
||||
},
|
||||
// bubble the moved col left or right
|
||||
_bubbleCols: function() {
|
||||
var i, j, col1, col2;
|
||||
var from = this.originalTable.startIndex;
|
||||
var to = this.originalTable.endIndex;
|
||||
/* Find children thead and tbody.
|
||||
* Only to process the immediate tr-children. Bugfix for inner tables
|
||||
*/
|
||||
var thtb = this.originalTable.el.children();
|
||||
if (this.options.excludeFooter) {
|
||||
thtb = thtb.not('tfoot');
|
||||
}
|
||||
if (from < to) {
|
||||
for (i = from; i < to; i++) {
|
||||
col1 = thtb.find('> tr > td:nth-child(' + i + ')')
|
||||
.add(thtb.find('> tr > th:nth-child(' + i + ')'));
|
||||
col2 = thtb.find('> tr > td:nth-child(' + (i + 1) + ')')
|
||||
.add(thtb.find('> tr > th:nth-child(' + (i + 1) + ')'));
|
||||
for (j = 0; j < col1.length; j++) {
|
||||
swapNodes(col1[j], col2[j]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = from; i > to; i--) {
|
||||
col1 = thtb.find('> tr > td:nth-child(' + i + ')')
|
||||
.add(thtb.find('> tr > th:nth-child(' + i + ')'));
|
||||
col2 = thtb.find('> tr > td:nth-child(' + (i - 1) + ')')
|
||||
.add(thtb.find('> tr > th:nth-child(' + (i - 1) + ')'));
|
||||
for (j = 0; j < col1.length; j++) {
|
||||
swapNodes(col1[j], col2[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_rearrangeTableBackroundProcessing: function() {
|
||||
var _this = this;
|
||||
return function() {
|
||||
_this._bubbleCols();
|
||||
_this.options.beforeStop(_this.originalTable);
|
||||
_this.sortableTable.el.remove();
|
||||
restoreTextSelection();
|
||||
// persist state if necessary
|
||||
if (_this.options.persistState !== null) {
|
||||
$.isFunction(_this.options.persistState) ? _this.options.persistState(_this.originalTable) : _this.persistState();
|
||||
}
|
||||
};
|
||||
},
|
||||
_rearrangeTable: function() {
|
||||
var _this = this;
|
||||
return function() {
|
||||
// remove handler-class -> handler is now finished
|
||||
_this.originalTable.selectedHandle.removeClass('dragtable-handle-selected');
|
||||
// add disabled class -> reorgorganisation starts soon
|
||||
_this.sortableTable.el.sortable("disable");
|
||||
_this.sortableTable.el.addClass('dragtable-disabled');
|
||||
_this.options.beforeReorganize(_this.originalTable, _this.sortableTable);
|
||||
// do reorganisation asynchronous
|
||||
// for chrome a little bit more than 1 ms because we want to force a rerender
|
||||
_this.originalTable.endIndex = _this.sortableTable.movingRow.prevAll().length + 1;
|
||||
setTimeout(_this._rearrangeTableBackroundProcessing(), 50);
|
||||
};
|
||||
},
|
||||
/*
|
||||
* Disrupts the table. The original table stays the same.
|
||||
* But on a layer above the original table we are constructing a list (ul > li)
|
||||
* each li with a separate table representig a single col of the original table.
|
||||
*/
|
||||
_generateSortable: function(e) {
|
||||
!e.cancelBubble && (e.cancelBubble = true);
|
||||
var _this = this;
|
||||
// table attributes
|
||||
var attrs = this.originalTable.el[0].attributes;
|
||||
var attrsString = '';
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
if (attrs[i].nodeValue && attrs[i].nodeName != 'id' && attrs[i].nodeName != 'width') {
|
||||
attrsString += attrs[i].nodeName + '="' + attrs[i].nodeValue + '" ';
|
||||
}
|
||||
}
|
||||
|
||||
// row attributes
|
||||
var rowAttrsArr = [];
|
||||
//compute height, special handling for ie needed :-(
|
||||
var heightArr = [];
|
||||
this.originalTable.el.find('tr').slice(0, this.options.maxMovingRows).each(function(i, v) {
|
||||
// row attributes
|
||||
var attrs = this.attributes;
|
||||
var attrsString = "";
|
||||
for (var j = 0; j < attrs.length; j++) {
|
||||
if (attrs[j].nodeValue && attrs[j].nodeName != 'id') {
|
||||
attrsString += " " + attrs[j].nodeName + '="' + attrs[j].nodeValue + '"';
|
||||
}
|
||||
}
|
||||
rowAttrsArr.push(attrsString);
|
||||
heightArr.push($(this).height());
|
||||
});
|
||||
|
||||
// compute width, no special handling for ie needed :-)
|
||||
var widthArr = [];
|
||||
// compute total width, needed for not wrapping around after the screen ends (floating)
|
||||
var totalWidth = 0;
|
||||
/* Find children thead and tbody.
|
||||
* Only to process the immediate tr-children. Bugfix for inner tables
|
||||
*/
|
||||
var thtb = _this.originalTable.el.children();
|
||||
if (this.options.excludeFooter) {
|
||||
thtb = thtb.not('tfoot');
|
||||
}
|
||||
thtb.find('> tr > th').each(function(i, v) {
|
||||
var w = $(this).is(':visible') ? $(this).outerWidth() : 0;
|
||||
widthArr.push(w);
|
||||
totalWidth += w;
|
||||
});
|
||||
if(_this.options.exact) {
|
||||
var difference = totalWidth - _this.originalTable.el.outerWidth();
|
||||
widthArr[0] -= difference;
|
||||
}
|
||||
// one extra px on right and left side
|
||||
totalWidth += 2
|
||||
|
||||
var sortableHtml = '<ul class="dragtable-sortable" style="position:absolute; width:' + totalWidth + 'px;">';
|
||||
// assemble the needed html
|
||||
thtb.find('> tr > th').each(function(i, v) {
|
||||
var width_li = $(this).is(':visible') ? $(this).outerWidth() : 0;
|
||||
sortableHtml += '<li style="width:' + width_li + 'px;">';
|
||||
sortableHtml += '<table ' + attrsString + '>';
|
||||
var row = thtb.find('> tr > th:nth-child(' + (i + 1) + ')');
|
||||
if (_this.options.maxMovingRows > 1) {
|
||||
row = row.add(thtb.find('> tr > td:nth-child(' + (i + 1) + ')').slice(0, _this.options.maxMovingRows - 1));
|
||||
}
|
||||
row.each(function(j) {
|
||||
// TODO: May cause duplicate style-Attribute
|
||||
var row_content = $(this).clone().wrap('<div></div>').parent().html();
|
||||
if (row_content.toLowerCase().indexOf('<th') === 0) sortableHtml += "<thead>";
|
||||
sortableHtml += '<tr ' + rowAttrsArr[j] + '" style="height:' + heightArr[j] + 'px;">';
|
||||
sortableHtml += row_content;
|
||||
if (row_content.toLowerCase().indexOf('<th') === 0) sortableHtml += "</thead>";
|
||||
sortableHtml += '</tr>';
|
||||
});
|
||||
sortableHtml += '</table>';
|
||||
sortableHtml += '</li>';
|
||||
});
|
||||
sortableHtml += '</ul>';
|
||||
this.sortableTable.el = this.originalTable.el.before(sortableHtml).prev();
|
||||
// set width if necessary
|
||||
this.sortableTable.el.find('> li > table').each(function(i, v) {
|
||||
$(this).css('width', widthArr[i] + 'px');
|
||||
});
|
||||
|
||||
// assign this.sortableTable.selectedHandle
|
||||
this.sortableTable.selectedHandle = this.sortableTable.el.find('th .dragtable-handle-selected');
|
||||
|
||||
var items = !this.options.dragaccept ? 'li' : 'li:has(' + this.options.dragaccept + ')';
|
||||
this.sortableTable.el.sortable({
|
||||
items: items,
|
||||
stop: this._rearrangeTable(),
|
||||
// pass thru options for sortable widget
|
||||
revert: this.options.revert,
|
||||
tolerance: this.options.tolerance,
|
||||
containment: this.options.containment,
|
||||
cursor: this.options.cursor,
|
||||
cursorAt: this.options.cursorAt,
|
||||
distance: this.options.distance,
|
||||
axis: this.options.axis
|
||||
});
|
||||
|
||||
// assign start index
|
||||
this.originalTable.startIndex = $(e.target).closest('th').prevAll().length + 1;
|
||||
|
||||
this.options.beforeMoving(this.originalTable, this.sortableTable);
|
||||
// Start moving by delegating the original event to the new sortable table
|
||||
this.sortableTable.movingRow = this.sortableTable.el.find('> li:nth-child(' + this.originalTable.startIndex + ')');
|
||||
|
||||
// prevent the user from drag selecting "highlighting" surrounding page elements
|
||||
disableTextSelection();
|
||||
// clone the initial event and trigger the sort with it
|
||||
this.sortableTable.movingRow.trigger($.extend($.Event(e.type), {
|
||||
which: 1,
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
pageX: e.pageX,
|
||||
pageY: e.pageY,
|
||||
screenX: e.screenX,
|
||||
screenY: e.screenY
|
||||
}));
|
||||
|
||||
// Some inner divs to deliver the posibillity to style the placeholder more sophisticated
|
||||
var placeholder = this.sortableTable.el.find('.ui-sortable-placeholder');
|
||||
if(!placeholder.height() <= 0) {
|
||||
placeholder.css('height', this.sortableTable.el.find('.ui-sortable-helper').height());
|
||||
}
|
||||
|
||||
placeholder.html('<div class="outer" style="height:100%;"><div class="inner" style="height:100%;"></div></div>');
|
||||
},
|
||||
bindTo: {},
|
||||
_create: function() {
|
||||
this.originalTable = {
|
||||
el: this.element,
|
||||
selectedHandle: $(),
|
||||
sortOrder: {},
|
||||
startIndex: 0,
|
||||
endIndex: 0
|
||||
};
|
||||
// bind draggable to 'th' by default
|
||||
this.bindTo = this.originalTable.el.find('th');
|
||||
// filter only the cols that are accepted
|
||||
if (this.options.dragaccept) {
|
||||
this.bindTo = this.bindTo.filter(this.options.dragaccept);
|
||||
}
|
||||
// bind draggable to handle if exists
|
||||
if (this.bindTo.find(this.options.dragHandle).length > 0) {
|
||||
this.bindTo = this.bindTo.find(this.options.dragHandle);
|
||||
}
|
||||
// restore state if necessary
|
||||
if (this.options.restoreState !== null) {
|
||||
$.isFunction(this.options.restoreState) ? this.options.restoreState(this.originalTable) : this._restoreState(this.options.restoreState);
|
||||
}
|
||||
var _this = this;
|
||||
this.bindTo.mousedown(function(evt) {
|
||||
// listen only to left mouse click
|
||||
if(evt.which!==1) return;
|
||||
if (_this.options.beforeStart(_this.originalTable) === false) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(this.downTimer);
|
||||
this.downTimer = setTimeout(function() {
|
||||
_this.originalTable.selectedHandle = $(this);
|
||||
_this.originalTable.selectedHandle.addClass('dragtable-handle-selected');
|
||||
_this._generateSortable(evt);
|
||||
}, _this.options.clickDelay);
|
||||
}).mouseup(function(evt) {
|
||||
clearTimeout(this.downTimer);
|
||||
});
|
||||
},
|
||||
redraw: function(){
|
||||
this.destroy();
|
||||
this._create();
|
||||
},
|
||||
destroy: function() {
|
||||
this.bindTo.unbind('mousedown');
|
||||
$.Widget.prototype.destroy.apply(this, arguments); // default destroy
|
||||
// now do other stuff particular to this widget
|
||||
}
|
||||
});
|
||||
|
||||
/** closure-scoped "private" functions **/
|
||||
|
||||
var body_onselectstart_save = $(document.body).attr('onselectstart'),
|
||||
body_unselectable_save = $(document.body).attr('unselectable');
|
||||
|
||||
// css properties to disable user-select on the body tag by appending a <style> tag to the <head>
|
||||
// remove any current document selections
|
||||
|
||||
function disableTextSelection() {
|
||||
// jQuery doesn't support the element.text attribute in MSIE 8
|
||||
// http://stackoverflow.com/questions/2692770/style-style-textcss-appendtohead-does-not-work-in-ie
|
||||
var $style = $('<style id="__dragtable_disable_text_selection__" type="text/css">body { -ms-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;user-select:none; }</style>');
|
||||
$(document.head).append($style);
|
||||
$(document.body).attr('onselectstart', 'return false;').attr('unselectable', 'on');
|
||||
if (window.getSelection) {
|
||||
window.getSelection().removeAllRanges();
|
||||
} else {
|
||||
document.selection.empty(); // MSIE http://msdn.microsoft.com/en-us/library/ms535869%28v=VS.85%29.aspx
|
||||
}
|
||||
}
|
||||
|
||||
// remove the <style> tag, and restore the original <body> onselectstart attribute
|
||||
|
||||
function restoreTextSelection() {
|
||||
$('#__dragtable_disable_text_selection__').remove();
|
||||
if (body_onselectstart_save) {
|
||||
$(document.body).attr('onselectstart', body_onselectstart_save);
|
||||
} else {
|
||||
$(document.body).removeAttr('onselectstart');
|
||||
}
|
||||
if (body_unselectable_save) {
|
||||
$(document.body).attr('unselectable', body_unselectable_save);
|
||||
} else {
|
||||
$(document.body).removeAttr('unselectable');
|
||||
}
|
||||
}
|
||||
|
||||
function swapNodes(a, b) {
|
||||
var aparent = a.parentNode;
|
||||
var asibling = a.nextSibling === b ? a : a.nextSibling;
|
||||
b.parentNode.insertBefore(a, b);
|
||||
aparent.insertBefore(b, asibling);
|
||||
}
|
||||
})(jQuery);
|
|
@ -454,12 +454,18 @@ $(document).ready(function () {
|
|||
$('#assigned_location').hide();
|
||||
$('.notification-callout').fadeOut();
|
||||
|
||||
$('[name="assigned_location"]').val('').trigger('change.select2');
|
||||
$('[name="assigned_user"]').val('').trigger('change.select2');
|
||||
|
||||
} else if (assignto_type == 'location') {
|
||||
$('#current_assets_box').fadeOut();
|
||||
$('#assigned_asset').hide();
|
||||
$('#assigned_user').hide();
|
||||
$('#assigned_location').show();
|
||||
$('.notification-callout').fadeOut();
|
||||
|
||||
$('[name="assigned_asset"]').val('').trigger('change.select2');
|
||||
$('[name="assigned_user"]').val('').trigger('change.select2');
|
||||
} else {
|
||||
|
||||
$('#assigned_asset').hide();
|
||||
|
@ -470,6 +476,8 @@ $(document).ready(function () {
|
|||
}
|
||||
$('.notification-callout').fadeIn();
|
||||
|
||||
$('[name="assigned_asset"]').val('').trigger('change.select2');
|
||||
$('[name="assigned_location"]').val('').trigger('change.select2');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,11 +40,17 @@ $(function () {
|
|||
select = link.data("select");
|
||||
refreshSelector = link.data("refresh");
|
||||
|
||||
|
||||
$('#createModal').load(link.attr('href'),function () {
|
||||
|
||||
// this sets the focus to be the name field
|
||||
$('#modal-name').focus();
|
||||
|
||||
//do we need to re-select2 this, after load? Probably.
|
||||
$('#createModal').find('select.select2').select2();
|
||||
// Initialize the ajaxy select2 with images.
|
||||
// This is a copy/paste of the code from snipeit.js, would be great to only have this in one place.
|
||||
|
||||
$('.js-data-ajax').each( function (i,item) {
|
||||
var link = $(item);
|
||||
var endpoint = link.data("endpoint");
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
return [
|
||||
'does_not_exist' => 'Maatskappy bestaan nie.',
|
||||
'deleted' => 'Deleted company',
|
||||
'assoc_users' => 'Hierdie maatskappy is tans geassosieer met ten minste een model en kan nie verwyder word nie. Dateer asseblief jou modelle op om nie meer hierdie maatskappy te verwys nie en probeer weer.',
|
||||
'create' => [
|
||||
'error' => 'Maatskappy is nie geskep nie, probeer asseblief weer.',
|
||||
|
|
|
@ -10,6 +10,9 @@ return [
|
|||
'bulk_update' => 'Grootskaalse opdateringsbates',
|
||||
'bulk_update_help' => 'Met hierdie vorm kan u verskeie bates gelyktydig bywerk. Vul slegs die velde in wat u moet verander. Enige velde wat leeg is, bly onveranderd.',
|
||||
'bulk_update_warn' => 'You are about to edit the properties of a single asset.|You are about to edit the properties of :asset_count assets.',
|
||||
'bulk_update_with_custom_field' => 'Note the assets are :asset_model_count different types of models.',
|
||||
'bulk_update_model_prefix' => 'On Models',
|
||||
'bulk_update_custom_field_unique' => 'This is a unique field and can not be bulk edited.',
|
||||
'checkedout_to' => 'Gekontroleer na',
|
||||
'checkout_date' => 'Checkout Datum',
|
||||
'checkin_date' => 'Incheckdatum',
|
||||
|
|
|
@ -50,6 +50,7 @@ return [
|
|||
'success' => 'Jou lêer is ingevoer',
|
||||
'file_delete_success' => 'Jou lêer is suksesvol verwyder',
|
||||
'file_delete_error' => 'Die lêer kon nie uitgevee word nie',
|
||||
'file_missing' => 'The file selected is missing',
|
||||
'header_row_has_malformed_characters' => 'One or more attributes in the header row contain malformed UTF-8 characters',
|
||||
'content_row_has_malformed_characters' => 'One or more attributes in the first row of content contain malformed UTF-8 characters',
|
||||
],
|
||||
|
|
|
@ -14,6 +14,7 @@ return [
|
|||
'dl_csv' => 'Laai CSV af',
|
||||
'eol' => 'EOL',
|
||||
'id' => 'ID',
|
||||
'last_checkin_date' => 'Last Checkin Date',
|
||||
'location' => 'plek',
|
||||
'purchase_cost' => 'koste',
|
||||
'purchase_date' => 'gekoop',
|
||||
|
|
11
resources/lang/af/admin/labels/message.php
Normal file
11
resources/lang/af/admin/labels/message.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'invalid_return_count' => 'Invalid count returned from :name. Expected :expected, got :actual.',
|
||||
'invalid_return_type' => 'Invalid type returned from :name. Expected :expected, got :actual.',
|
||||
'invalid_return_value' => 'Invalid value returned from :name. Expected :expected, got :actual.',
|
||||
|
||||
'does_not_exist' => 'Label does not exist',
|
||||
|
||||
];
|
13
resources/lang/af/admin/labels/table.php
Normal file
13
resources/lang/af/admin/labels/table.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'labels_per_page' => 'Labels',
|
||||
'support_fields' => 'Fields',
|
||||
'support_asset_tag' => 'Tag',
|
||||
'support_1d_barcode' => '1D',
|
||||
'support_2d_barcode' => '2D',
|
||||
'support_logo' => 'Logo',
|
||||
'support_title' => 'Title',
|
||||
|
||||
];
|
|
@ -26,6 +26,7 @@ return array(
|
|||
'modal' => 'This will action checkin one seat. | This action will checkin all :checkedout_seats_count seats for this license.',
|
||||
'enabled_tooltip' => 'Checkin ALL seats for this license from both users and assets',
|
||||
'disabled_tooltip' => 'This is disabled because there are no seats currently checked out',
|
||||
'disabled_tooltip_reassignable' => 'This is disabled because the License is not reassignable',
|
||||
'success' => 'License successfully checked in! | All licenses were successfully checked in!',
|
||||
'log_msg' => 'Checked in via bulk license checkout in license GUI',
|
||||
],
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
return array(
|
||||
|
||||
'support_url_help' => 'Use <code>{LOCALE}</code> and <code>{SERIAL}</code> in your URL as variables to have those values auto-populate when viewing assets.',
|
||||
'support_url_help' => 'Variables <code>{LOCALE}</code>, <code>{SERIAL}</code>, <code>{MODEL_NUMBER}</code>, and <code>{MODEL_NAME}</code> may be used in your URL to have those values auto-populate when viewing assets - for example https://support.apple.com/{LOCALE}/{SERIAL}.',
|
||||
'does_not_exist' => 'Vervaardiger bestaan nie.',
|
||||
'assoc_users' => 'Hierdie vervaardiger word tans geassosieer met ten minste een model en kan nie verwyder word nie. Dateer asseblief jou modelle op om nie meer hierdie vervaardiger te gebruik nie en probeer weer.',
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
return array(
|
||||
|
||||
'deleted' => 'Deleted asset model',
|
||||
'does_not_exist' => 'Model bestaan nie.',
|
||||
'no_association' => 'WARNING! The asset model for this item is invalid or missing!',
|
||||
'no_association_fix' => 'This will break things in weird and horrible ways. Edit this asset now to assign it a model.',
|
||||
|
|
|
@ -330,9 +330,36 @@ return [
|
|||
'setup_migration_create_user' => 'Next: Create User',
|
||||
'ldap_settings_link' => 'LDAP Settings Page',
|
||||
'slack_test' => 'Test <i class="fab fa-slack"></i> Integration',
|
||||
'label2_enable' => 'New Label Engine',
|
||||
'label2_enable_help' => 'Switch to the new label engine. <b>Note: You will need to save this setting before setting others.</b>',
|
||||
'label2_template' => 'Template',
|
||||
'label2_template_help' => 'Select which template to use for label generation',
|
||||
'label2_title' => 'Title',
|
||||
'label2_title_help' => 'The title to show on labels that support it',
|
||||
'label2_title_help_phold' => 'The placeholder <code>{COMPANY}</code> will be replaced with the asset's company name',
|
||||
'label2_asset_logo' => 'Use Asset Logo',
|
||||
'label2_asset_logo_help' => 'Use the logo of the asset's assigned company, rather than the value at <code>:setting_name</code>',
|
||||
'label2_1d_type' => '1D Barcode Type',
|
||||
'label2_1d_type_help' => 'Format for 1D barcodes',
|
||||
'label2_2d_type' => '2D Barcode Type',
|
||||
'label2_2d_type_help' => 'Format for 2D barcodes',
|
||||
'label2_2d_target' => '2D Barcode Target',
|
||||
'label2_2d_target_help' => 'The URL the 2D barcode points to when scanned',
|
||||
'label2_fields' => 'Field Definitions',
|
||||
'label2_fields_help' => 'Fields can be added, removed, and reordered in the left column. For each field, multiple options for Label and DataSource can be added, removed, and reordered in the right column.',
|
||||
'help_asterisk_bold' => 'Text entered as <code>**text**</code> will be displayed as bold',
|
||||
'help_blank_to_use' => 'Leave blank to use the value from <code>:setting_name</code>',
|
||||
'help_default_will_use' => '<code>:default</code> will use the value from <code>:setting_name</code>. <br>Note that the value of the barcodes must comply with the respective barcode spec in order to be successfully generated. Please see <a href="https://snipe-it.readme.io/docs/barcodes">the documentation <i class="fa fa-external-link"></i></a> for more details. ',
|
||||
'default' => 'Default',
|
||||
'none' => 'None',
|
||||
'google_callback_help' => 'This should be entered as the callback URL in your Google OAuth app settings in your organization's <strong><a href="https://console.cloud.google.com/" target="_blank">Google developer console <i class="fa fa-external-link" aria-hidden="true"></i></a></strong>.',
|
||||
'google_login' => 'Google Workspace Login Settings',
|
||||
'enable_google_login' => 'Enable users to login with Google Workspace',
|
||||
'enable_google_login_help' => 'Users will not be automatically provisioned. They must have an existing account here AND in Google Workspace, and their username here must match their Google Workspace email address. ',
|
||||
'mail_reply_to' => 'Mail Reply-To Address',
|
||||
'mail_from' => 'Mail From Address',
|
||||
'database_driver' => 'Database Driver',
|
||||
'bs_table_storage' => 'Table Storage',
|
||||
'timezone' => 'Timezone',
|
||||
|
||||
];
|
||||
|
|
|
@ -35,10 +35,12 @@ return [
|
|||
],
|
||||
'webhook' => [
|
||||
'sending' => 'Sending :app test message...',
|
||||
'success' => 'Your :webhook_name Integration works!',
|
||||
'success_pt1' => 'Success! Check the ',
|
||||
'success_pt2' => ' channel for your test message, and be sure to click SAVE below to store your settings.',
|
||||
'500' => '500 Server Error.',
|
||||
'error' => 'Something went wrong. :app responded with: :error_message',
|
||||
'error_redirect' => 'ERROR: 301/302 :endpoint returns a redirect. For security reasons, we don’t follow redirects. Please use the actual endpoint.',
|
||||
'error_misc' => 'Something went wrong. :( ',
|
||||
]
|
||||
];
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
return array(
|
||||
|
||||
'deleted' => 'Deleted supplier',
|
||||
'does_not_exist' => 'Verskaffer bestaan nie.',
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ return array(
|
|||
'show_deleted' => 'Wys verwyderde gebruikers',
|
||||
'title' => 'Titel',
|
||||
'to_restore_them' => 'om hulle te herstel.',
|
||||
'total_assets_cost' => "Total Assets Cost",
|
||||
'updateuser' => 'Update gebruiker',
|
||||
'username' => 'Gebruikersnaam',
|
||||
'user_deleted_text' => 'Hierdie gebruiker is gemerk as verwyder.',
|
||||
|
|
|
@ -120,6 +120,9 @@ return [
|
|||
'firstname_lastname_underscore_format' => 'First Name Last Name (jane_smith@example.com)',
|
||||
'lastnamefirstinitial_format' => 'Last Name First Initial (smithj@example.com)',
|
||||
'firstintial_dot_lastname_format' => 'First Initial Last Name (j.smith@example.com)',
|
||||
'firstname_lastname_display' => 'First Name Last Name (Jane Smith)',
|
||||
'lastname_firstname_display' => 'Last Name First Name (Smith Jane)',
|
||||
'name_display_format' => 'Name Display Format',
|
||||
'first' => 'eerste',
|
||||
'firstnamelastname' => 'First Name Last Name (janesmith@example.com)',
|
||||
'lastname_firstinitial' => 'Last Name First Initial (smith_j@example.com)',
|
||||
|
@ -265,6 +268,8 @@ return [
|
|||
'supplier' => 'verskaffer',
|
||||
'suppliers' => 'Verskaffers',
|
||||
'sure_to_delete' => 'Is jy seker jy wil verwyder',
|
||||
'sure_to_delete_var' => 'Are you sure you wish to delete :item?',
|
||||
'delete_what' => 'Delete :item',
|
||||
'submit' => 'Indien',
|
||||
'target' => 'teiken',
|
||||
'time_and_date_display' => 'Tyd en datum vertoon',
|
||||
|
@ -283,6 +288,7 @@ return [
|
|||
'user' => 'gebruiker',
|
||||
'accepted' => 'aanvaarde',
|
||||
'declined' => 'afgeneem',
|
||||
'unassigned' => 'Unassigned',
|
||||
'unaccepted_asset_report' => 'Onaanvaarde Bates',
|
||||
'users' => 'gebruikers',
|
||||
'viewall' => 'View All',
|
||||
|
@ -364,9 +370,10 @@ return [
|
|||
'licenses_count' => 'Licenses Count',
|
||||
'notification_error' => 'Error:',
|
||||
'notification_error_hint' => 'Please check the form below for errors',
|
||||
'notification_success' => 'Success:',
|
||||
'notification_warning' => 'Warning:',
|
||||
'notification_info' => 'Info:',
|
||||
'notification_bulk_error_hint' => 'The following fields had validation errors and were not edited:',
|
||||
'notification_success' => 'Success',
|
||||
'notification_warning' => 'Warning',
|
||||
'notification_info' => 'Info',
|
||||
'asset_information' => 'Asset Information',
|
||||
'model_name' => 'Model Name',
|
||||
'asset_name' => 'Asset Name',
|
||||
|
@ -452,6 +459,8 @@ return [
|
|||
'serial_number' => 'Serial Number',
|
||||
'item_notes' => ':item Notes',
|
||||
'item_name_var' => ':item Name',
|
||||
'error_user_company' => 'Checkout target company and asset company do not match',
|
||||
'error_user_company_accept_view' => 'An Asset assigned to you belongs to a different company so you can\'t accept nor deny it, please check with your manager',
|
||||
'importer' => [
|
||||
'checked_out_to_fullname' => 'Checked Out to: Full Name',
|
||||
'checked_out_to_first_name' => 'Checked Out to: First Name',
|
||||
|
@ -474,5 +483,10 @@ return [
|
|||
'address2' => 'Address Line 2',
|
||||
'import_note' => 'Imported using csv importer',
|
||||
],
|
||||
'percent_complete' => '% complete',
|
||||
'uploading' => 'Uploading... ',
|
||||
'upload_error' => 'Error uploading file. Please check that there are no empty trailing rows.',
|
||||
'copy_to_clipboard' => 'Copy to Clipboard',
|
||||
'copied' => 'Copied!',
|
||||
|
||||
];
|
||||
|
|
|
@ -30,6 +30,7 @@ return [
|
|||
'ga-IE'=> 'Irish',
|
||||
'it'=> 'Italian',
|
||||
'ja'=> 'Japanese',
|
||||
'km' => 'Khmer',
|
||||
'ko'=> 'Korean',
|
||||
'lv'=>'Latvian',
|
||||
'lt'=> 'Lithuanian',
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
return [
|
||||
'does_not_exist' => 'Company does not exist.',
|
||||
'deleted' => 'Deleted company',
|
||||
'assoc_users' => 'This company is currently associated with at least one model and cannot be deleted. Please update your models to no longer reference this company and try again. ',
|
||||
'create' => [
|
||||
'error' => 'Company was not created, please try again.',
|
||||
|
|
|
@ -10,6 +10,9 @@ return [
|
|||
'bulk_update' => 'Bulk Update Assets',
|
||||
'bulk_update_help' => 'This form allows you to update multiple assets at once. Only fill in the fields you need to change. Any fields left blank will remain unchanged. ',
|
||||
'bulk_update_warn' => 'You are about to edit the properties of a single asset.|You are about to edit the properties of :asset_count assets.',
|
||||
'bulk_update_with_custom_field' => 'Note the assets are :asset_model_count different types of models.',
|
||||
'bulk_update_model_prefix' => 'On Models',
|
||||
'bulk_update_custom_field_unique' => 'This is a unique field and can not be bulk edited.',
|
||||
'checkedout_to' => 'Checked Out To',
|
||||
'checkout_date' => 'Checkout Date',
|
||||
'checkin_date' => 'Checkin Date',
|
||||
|
|
|
@ -51,6 +51,7 @@ return [
|
|||
'success' => 'Your file has been imported',
|
||||
'file_delete_success' => 'Your file has been been successfully deleted',
|
||||
'file_delete_error' => 'The file was unable to be deleted',
|
||||
'file_missing' => 'The file selected is missing',
|
||||
'header_row_has_malformed_characters' => 'One or more attributes in the header row contain malformed UTF-8 characters',
|
||||
'content_row_has_malformed_characters' => 'One or more attributes in the first row of content contain malformed UTF-8 characters',
|
||||
],
|
||||
|
|
|
@ -14,6 +14,7 @@ return [
|
|||
'dl_csv' => 'Download CSV',
|
||||
'eol' => 'EOL',
|
||||
'id' => 'ID',
|
||||
'last_checkin_date' => 'Last Checkin Date',
|
||||
'location' => 'Location',
|
||||
'purchase_cost' => 'Cost',
|
||||
'purchase_date' => 'Purchased',
|
||||
|
|
11
resources/lang/am/admin/labels/message.php
Normal file
11
resources/lang/am/admin/labels/message.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'invalid_return_count' => 'Invalid count returned from :name. Expected :expected, got :actual.',
|
||||
'invalid_return_type' => 'Invalid type returned from :name. Expected :expected, got :actual.',
|
||||
'invalid_return_value' => 'Invalid value returned from :name. Expected :expected, got :actual.',
|
||||
|
||||
'does_not_exist' => 'Label does not exist',
|
||||
|
||||
];
|
13
resources/lang/am/admin/labels/table.php
Normal file
13
resources/lang/am/admin/labels/table.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'labels_per_page' => 'Labels',
|
||||
'support_fields' => 'Fields',
|
||||
'support_asset_tag' => 'Tag',
|
||||
'support_1d_barcode' => '1D',
|
||||
'support_2d_barcode' => '2D',
|
||||
'support_logo' => 'Logo',
|
||||
'support_title' => 'Title',
|
||||
|
||||
];
|
|
@ -26,6 +26,7 @@ return array(
|
|||
'modal' => 'This will action checkin one seat. | This action will checkin all :checkedout_seats_count seats for this license.',
|
||||
'enabled_tooltip' => 'Checkin ALL seats for this license from both users and assets',
|
||||
'disabled_tooltip' => 'This is disabled because there are no seats currently checked out',
|
||||
'disabled_tooltip_reassignable' => 'This is disabled because the License is not reassignable',
|
||||
'success' => 'License successfully checked in! | All licenses were successfully checked in!',
|
||||
'log_msg' => 'Checked in via bulk license checkout in license GUI',
|
||||
],
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
return array(
|
||||
|
||||
'support_url_help' => 'Use <code>{LOCALE}</code> and <code>{SERIAL}</code> in your URL as variables to have those values auto-populate when viewing assets.',
|
||||
'support_url_help' => 'Variables <code>{LOCALE}</code>, <code>{SERIAL}</code>, <code>{MODEL_NUMBER}</code>, and <code>{MODEL_NAME}</code> may be used in your URL to have those values auto-populate when viewing assets - for example https://support.apple.com/{LOCALE}/{SERIAL}.',
|
||||
'does_not_exist' => 'Manufacturer does not exist.',
|
||||
'assoc_users' => 'This manufacturer is currently associated with at least one model and cannot be deleted. Please update your models to no longer reference this manufacturer and try again. ',
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
return array(
|
||||
|
||||
'deleted' => 'Deleted asset model',
|
||||
'does_not_exist' => 'Model does not exist.',
|
||||
'no_association' => 'WARNING! The asset model for this item is invalid or missing!',
|
||||
'no_association_fix' => 'This will break things in weird and horrible ways. Edit this asset now to assign it a model.',
|
||||
|
|
|
@ -330,9 +330,36 @@ return [
|
|||
'setup_migration_create_user' => 'Next: Create User',
|
||||
'ldap_settings_link' => 'LDAP Settings Page',
|
||||
'slack_test' => 'Test <i class="fab fa-slack"></i> Integration',
|
||||
'label2_enable' => 'New Label Engine',
|
||||
'label2_enable_help' => 'Switch to the new label engine. <b>Note: You will need to save this setting before setting others.</b>',
|
||||
'label2_template' => 'Template',
|
||||
'label2_template_help' => 'Select which template to use for label generation',
|
||||
'label2_title' => 'Title',
|
||||
'label2_title_help' => 'The title to show on labels that support it',
|
||||
'label2_title_help_phold' => 'The placeholder <code>{COMPANY}</code> will be replaced with the asset's company name',
|
||||
'label2_asset_logo' => 'Use Asset Logo',
|
||||
'label2_asset_logo_help' => 'Use the logo of the asset's assigned company, rather than the value at <code>:setting_name</code>',
|
||||
'label2_1d_type' => '1D Barcode Type',
|
||||
'label2_1d_type_help' => 'Format for 1D barcodes',
|
||||
'label2_2d_type' => '2D Barcode Type',
|
||||
'label2_2d_type_help' => 'Format for 2D barcodes',
|
||||
'label2_2d_target' => '2D Barcode Target',
|
||||
'label2_2d_target_help' => 'The URL the 2D barcode points to when scanned',
|
||||
'label2_fields' => 'Field Definitions',
|
||||
'label2_fields_help' => 'Fields can be added, removed, and reordered in the left column. For each field, multiple options for Label and DataSource can be added, removed, and reordered in the right column.',
|
||||
'help_asterisk_bold' => 'Text entered as <code>**text**</code> will be displayed as bold',
|
||||
'help_blank_to_use' => 'Leave blank to use the value from <code>:setting_name</code>',
|
||||
'help_default_will_use' => '<code>:default</code> will use the value from <code>:setting_name</code>. <br>Note that the value of the barcodes must comply with the respective barcode spec in order to be successfully generated. Please see <a href="https://snipe-it.readme.io/docs/barcodes">the documentation <i class="fa fa-external-link"></i></a> for more details. ',
|
||||
'default' => 'Default',
|
||||
'none' => 'None',
|
||||
'google_callback_help' => 'This should be entered as the callback URL in your Google OAuth app settings in your organization's <strong><a href="https://console.cloud.google.com/" target="_blank">Google developer console <i class="fa fa-external-link" aria-hidden="true"></i></a></strong>.',
|
||||
'google_login' => 'Google Workspace Login Settings',
|
||||
'enable_google_login' => 'Enable users to login with Google Workspace',
|
||||
'enable_google_login_help' => 'Users will not be automatically provisioned. They must have an existing account here AND in Google Workspace, and their username here must match their Google Workspace email address. ',
|
||||
'mail_reply_to' => 'Mail Reply-To Address',
|
||||
'mail_from' => 'Mail From Address',
|
||||
'database_driver' => 'Database Driver',
|
||||
'bs_table_storage' => 'Table Storage',
|
||||
'timezone' => 'Timezone',
|
||||
|
||||
];
|
||||
|
|
|
@ -35,10 +35,12 @@ return [
|
|||
],
|
||||
'webhook' => [
|
||||
'sending' => 'Sending :app test message...',
|
||||
'success' => 'Your :webhook_name Integration works!',
|
||||
'success_pt1' => 'Success! Check the ',
|
||||
'success_pt2' => ' channel for your test message, and be sure to click SAVE below to store your settings.',
|
||||
'500' => '500 Server Error.',
|
||||
'error' => 'Something went wrong. :app responded with: :error_message',
|
||||
'error_redirect' => 'ERROR: 301/302 :endpoint returns a redirect. For security reasons, we don’t follow redirects. Please use the actual endpoint.',
|
||||
'error_misc' => 'Something went wrong. :( ',
|
||||
]
|
||||
];
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
return array(
|
||||
|
||||
'deleted' => 'Deleted supplier',
|
||||
'does_not_exist' => 'Supplier does not exist.',
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ return array(
|
|||
'show_deleted' => 'Show Deleted Users',
|
||||
'title' => 'Title',
|
||||
'to_restore_them' => 'to restore them.',
|
||||
'total_assets_cost' => "Total Assets Cost",
|
||||
'updateuser' => 'Update User',
|
||||
'username' => 'Username',
|
||||
'user_deleted_text' => 'This user has been marked as deleted.',
|
||||
|
|
|
@ -120,6 +120,9 @@ return [
|
|||
'firstname_lastname_underscore_format' => 'First Name Last Name (jane_smith@example.com)',
|
||||
'lastnamefirstinitial_format' => 'Last Name First Initial (smithj@example.com)',
|
||||
'firstintial_dot_lastname_format' => 'First Initial Last Name (j.smith@example.com)',
|
||||
'firstname_lastname_display' => 'First Name Last Name (Jane Smith)',
|
||||
'lastname_firstname_display' => 'Last Name First Name (Smith Jane)',
|
||||
'name_display_format' => 'Name Display Format',
|
||||
'first' => 'First',
|
||||
'firstnamelastname' => 'First Name Last Name (janesmith@example.com)',
|
||||
'lastname_firstinitial' => 'Last Name First Initial (smith_j@example.com)',
|
||||
|
@ -265,6 +268,8 @@ return [
|
|||
'supplier' => 'Supplier',
|
||||
'suppliers' => 'Suppliers',
|
||||
'sure_to_delete' => 'Are you sure you wish to delete',
|
||||
'sure_to_delete_var' => 'Are you sure you wish to delete :item?',
|
||||
'delete_what' => 'Delete :item',
|
||||
'submit' => 'Submit',
|
||||
'target' => 'Target',
|
||||
'time_and_date_display' => 'Time and Date Display',
|
||||
|
@ -283,6 +288,7 @@ return [
|
|||
'user' => 'User',
|
||||
'accepted' => 'accepted',
|
||||
'declined' => 'declined',
|
||||
'unassigned' => 'Unassigned',
|
||||
'unaccepted_asset_report' => 'Unaccepted Assets',
|
||||
'users' => 'Users',
|
||||
'viewall' => 'View All',
|
||||
|
@ -364,9 +370,10 @@ return [
|
|||
'licenses_count' => 'Licenses Count',
|
||||
'notification_error' => 'Error:',
|
||||
'notification_error_hint' => 'Please check the form below for errors',
|
||||
'notification_success' => 'Success:',
|
||||
'notification_warning' => 'Warning:',
|
||||
'notification_info' => 'Info:',
|
||||
'notification_bulk_error_hint' => 'The following fields had validation errors and were not edited:',
|
||||
'notification_success' => 'Success',
|
||||
'notification_warning' => 'Warning',
|
||||
'notification_info' => 'Info',
|
||||
'asset_information' => 'Asset Information',
|
||||
'model_name' => 'Model Name',
|
||||
'asset_name' => 'Asset Name',
|
||||
|
@ -452,6 +459,8 @@ return [
|
|||
'serial_number' => 'Serial Number',
|
||||
'item_notes' => ':item Notes',
|
||||
'item_name_var' => ':item Name',
|
||||
'error_user_company' => 'Checkout target company and asset company do not match',
|
||||
'error_user_company_accept_view' => 'An Asset assigned to you belongs to a different company so you can\'t accept nor deny it, please check with your manager',
|
||||
'importer' => [
|
||||
'checked_out_to_fullname' => 'Checked Out to: Full Name',
|
||||
'checked_out_to_first_name' => 'Checked Out to: First Name',
|
||||
|
@ -474,5 +483,10 @@ return [
|
|||
'address2' => 'Address Line 2',
|
||||
'import_note' => 'Imported using csv importer',
|
||||
],
|
||||
'percent_complete' => '% complete',
|
||||
'uploading' => 'Uploading... ',
|
||||
'upload_error' => 'Error uploading file. Please check that there are no empty trailing rows.',
|
||||
'copy_to_clipboard' => 'Copy to Clipboard',
|
||||
'copied' => 'Copied!',
|
||||
|
||||
];
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue