Compare commits
252 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 78d1256b74 | |||
| a3f9aad418 | |||
| dba8cb83bf | |||
| 1954c607cd | |||
| 744124f407 | |||
| 3c14921a8c | |||
| b595fe7488 | |||
| b0b194cef7 | |||
| eb0a3a27d3 | |||
| 72fbcd72e0 | |||
| 09e660a38c | |||
| add1810fcc | |||
| eead2ce93e | |||
| 5e60d96614 | |||
| 85c721da99 | |||
| f3f09dd9a5 | |||
| 29ad804ca8 | |||
| a8c77d6e26 | |||
| b949380db8 | |||
| b7f6137a63 | |||
| 181cd7f0dc | |||
| 10692dc587 | |||
| 8d0793e004 | |||
| 02da163ee0 | |||
| 3199e94b3c | |||
| ac2a1503e2 | |||
| ea10167607 | |||
| e617b913cd | |||
| 8f6208a3c9 | |||
| 39c71481c9 | |||
| a38e49290e | |||
| f974427964 | |||
| 1f311c8657 | |||
| c0406734bc | |||
| 66e80628f6 | |||
| 620c43fd6d | |||
| dfb9d5622a | |||
| af0aa7da4e | |||
| 75ddb50738 | |||
| 600238dd9b | |||
| 5a88e98ad9 | |||
| 84a0544621 | |||
| 8a1c7ee448 | |||
| 2fb29dad0a | |||
| 7d160abdaf | |||
| 6c5d2c6716 | |||
| f3feff7988 | |||
| 7d24f50cdc | |||
| 7c7375ed43 | |||
| e2e4adca4e | |||
| a350b9bc3d | |||
| 7854543122 | |||
| 8b5636c0ab | |||
| 9f948fd2ba | |||
| 60fb67461a | |||
| 5c896fc965 | |||
| c779988771 | |||
| e6eb15d053 | |||
| 05b957df19 | |||
| 96da8a5fab | |||
| 62bf61402e | |||
| 227be798f6 | |||
| 53f304d137 | |||
| 137d362369 | |||
| 5b2cf54f50 | |||
| b4bc785f7c | |||
| 98a8e4c2ec | |||
| bed6b04c3d | |||
| babb3ffb9c | |||
| 15c96f753c | |||
| 354bdeffbf | |||
| 512af90d31 | |||
| ed837b7527 | |||
| fa5dd99f00 | |||
| a19282710b | |||
| 2f3cfb0a4e | |||
| af4db94d17 | |||
| bcbf27acca | |||
| 80b037c5a5 | |||
| 20bacfeecf | |||
| 8a128ae8c2 | |||
| beacfbb082 | |||
| df0d565ae5 | |||
| 9ee755c112 | |||
| 130aca2943 | |||
| 5ea76ecb66 | |||
| b8ff3ef41a | |||
| 3e8156be54 | |||
| 47e192b530 | |||
| b33f222fc0 | |||
| 20eab1f403 | |||
| a283fdb75a | |||
| a29a115846 | |||
| 05ff9183fb | |||
| 793d299c1d | |||
| 7d5f862f34 | |||
| b0ab900a0f | |||
| 0ea5012ba2 | |||
| 7ecb96d45a | |||
| 5f0d7fde39 | |||
| fe3c301ca2 | |||
| 3adf8847b0 | |||
| 9ae68f0000 | |||
| 36415a1f7a | |||
| 39d1aa932c | |||
| 82b37c3b58 | |||
| c73c2b003a | |||
| 65b39d3a30 | |||
| 6a59119c58 | |||
| 8b4387ec32 | |||
| dc82f8f077 | |||
| 07e1f67e13 | |||
| 412f4c65c8 | |||
| a6d9c1f882 | |||
| bb5c142f52 | |||
| a5e1528c0d | |||
| 904c20e879 | |||
| 612daa6824 | |||
| 02b6de2385 | |||
| da5db1920e | |||
| d20545741e | |||
| 03b42d2c6c | |||
| e9dbeebbc4 | |||
| bb53fa245b | |||
| bc796498a3 | |||
| c25266054b | |||
| 0204414196 | |||
| c6b2017494 | |||
| 84fd48602e | |||
| c8e8eb58aa | |||
| 0b087ca77d | |||
| 444083ec5d | |||
| bf01a11fec | |||
| 8f232421d2 | |||
| dbc688ad6e | |||
| 6217a721ac | |||
| c2ba937ac6 | |||
| d860786221 | |||
| 621ce1777f | |||
| 4f610ac1af | |||
| 7341cd1712 | |||
| bf112b7b4b | |||
| ad9e0cc39a | |||
| 1439681113 | |||
| 3b750541c9 | |||
| 79765201ac | |||
| 0086b9d848 | |||
| c8ddb44783 | |||
| d4829a4bac | |||
| 486f0c0035 | |||
| dc3a695ab0 | |||
| 3feee682b6 | |||
| 4ea5cb9538 | |||
| f6461a755a | |||
| 39cf5ce66e | |||
| c68d9892b5 | |||
| 33b20b6268 | |||
| 280df20a0b | |||
| 7027cd80d4 | |||
| bfbcfe7bae | |||
| e1f64b6d2b | |||
| 6944c438dd | |||
| 49b7ff1192 | |||
| 662cdbaa0e | |||
| e912eb5ef8 | |||
| 5ab68d83a5 | |||
| f7c432f7fd | |||
| 592ccb6ebe | |||
| d22d70dd92 | |||
| 7ec5606ce4 | |||
| 476bf95edf | |||
| cdf036ed7b | |||
| 639a3b9295 | |||
| e4f8c3bef7 | |||
| 462945022c | |||
| aa57687df0 | |||
| 3237a3b9de | |||
| ff30e109cc | |||
| 2d291f843a | |||
| 7219fc1c3c | |||
| ed6bfa7810 | |||
| ad15090c34 | |||
| 9d34bf4a19 | |||
| 7c9b1a52af | |||
| dd297dca31 | |||
| 1409d01078 | |||
| c9a03cf9b7 | |||
| 6a99132e76 | |||
| 2e269d2e63 | |||
| 7820636c9f | |||
| db1b35ccf6 | |||
| fadfe0a782 | |||
| 255a2ecdd9 | |||
| 97ffe33fc8 | |||
| 56d97a1f59 | |||
| 28d5d24617 | |||
| d97f6903d6 | |||
| 3bf84d96d9 | |||
| 8df643a2ab | |||
| 2d001c4fa1 | |||
| cbd6b57445 | |||
| dac684c08a | |||
| 772c29791a | |||
| 89a232ae14 | |||
| 4e4b8ddb77 | |||
| 6eaefa0bdd | |||
| 20a75bbbb7 | |||
| 5cc261dd3c | |||
| 6d958b6f65 | |||
| 8ddac4d7c7 | |||
| a321ad9dbe | |||
| 4dff66253c | |||
| 9a1e9f90bc | |||
| c54724919c | |||
| 139d1cdcf8 | |||
| 490c50a182 | |||
| af1e496eab | |||
| efea043549 | |||
| d4ee91f013 | |||
| d4561581ad | |||
| a17f167952 | |||
| 5beb068cde | |||
| a272bdc796 | |||
| 30a43089a0 | |||
| 416b32cbc8 | |||
| d203cece0e | |||
| 9f6f0f04c7 | |||
| a974c6d4cd | |||
| 34612acdcf | |||
| 9e23117f9c | |||
| b3996f1970 | |||
| e143017432 | |||
| c6c0a14ee0 | |||
| 9b8768dbdd | |||
| a3bfcc962d | |||
| ca4ed605a8 | |||
| d3e6d7442f | |||
| b558bc5334 | |||
| 204d7b5be6 | |||
| 7dccfec332 | |||
| 0b694bfd0b | |||
| dfb59d8a55 | |||
| 3cd191210c | |||
| 56a44ad421 | |||
| a12ee3c0da | |||
| a657c479be | |||
| bb7dabc73b | |||
| ab82c5fd88 | |||
| 78cfb19f69 | |||
| f2334082ee | |||
| 70d79c1890 | |||
| fb1fde26ce |
@@ -137,6 +137,8 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
|
||||
PUBLIC_AWS_DEFAULT_REGION=null
|
||||
PUBLIC_AWS_BUCKET=null
|
||||
PUBLIC_AWS_URL=null
|
||||
PUBLIC_AWS_ENDPOINT=null
|
||||
PUBLIC_AWS_PATH_STYLE=null
|
||||
PUBLIC_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
@@ -147,6 +149,8 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
|
||||
PRIVATE_AWS_DEFAULT_REGION=null
|
||||
PRIVATE_AWS_BUCKET=null
|
||||
PRIVATE_AWS_URL=null
|
||||
PRIVATE_AWS_ENDPOINT=null
|
||||
PRIVATE_AWS_PATH_STYLE=null
|
||||
PRIVATE_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
@@ -144,6 +144,8 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
|
||||
PUBLIC_AWS_DEFAULT_REGION=null
|
||||
PUBLIC_AWS_BUCKET=null
|
||||
PUBLIC_AWS_URL=null
|
||||
PUBLIC_AWS_ENDPOINT=null
|
||||
PUBLIC_AWS_PATH_STYLE=null
|
||||
PUBLIC_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
@@ -154,6 +156,8 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
|
||||
PRIVATE_AWS_DEFAULT_REGION=null
|
||||
PRIVATE_AWS_BUCKET=null
|
||||
PRIVATE_AWS_URL=null
|
||||
PRIVATE_AWS_ENDPOINT=null
|
||||
PRIVATE_AWS_PATH_STYLE=null
|
||||
PRIVATE_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
@@ -143,6 +143,8 @@ PUBLIC_AWS_ACCESS_KEY_ID=null
|
||||
PUBLIC_AWS_DEFAULT_REGION=null
|
||||
PUBLIC_AWS_BUCKET=null
|
||||
PUBLIC_AWS_URL=null
|
||||
PUBLIC_AWS_ENDPOINT=null
|
||||
PUBLIC_AWS_PATH_STYLE=null
|
||||
PUBLIC_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
@@ -153,6 +155,8 @@ PRIVATE_AWS_SECRET_ACCESS_KEY=null
|
||||
PRIVATE_AWS_DEFAULT_REGION=null
|
||||
PRIVATE_AWS_BUCKET=null
|
||||
PRIVATE_AWS_URL=null
|
||||
PRIVATE_AWS_ENDPOINT=null
|
||||
PRIVATE_AWS_PATH_STYLE=null
|
||||
PRIVATE_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
@@ -83,6 +83,7 @@ Since the release of the JSON REST API, several third-party developers have been
|
||||
- [jamf2snipe](https://github.com/grokability/jamf2snipe) - Python script to sync assets between a JAMFPro instance and a Snipe-IT instance
|
||||
- [jamf-snipe-rename](https://macblog.org/jamf-snipe-rename/) - Python script to rename computers in Jamf from Snipe-IT
|
||||
- [Snipe-IT plugin for Jira Service Desk](https://marketplace.atlassian.com/apps/1220964/snipe-it-for-jira)
|
||||
- [Rudder2Snipe](https://github.com/norbertoaquino/rudder2snipe) by [@norbertoaquino](https://github.com/norbertoaquino) - Rudder.io integration for Snipe-IT
|
||||
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
|
||||
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
|
||||
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-IT.
|
||||
|
||||
@@ -56,7 +56,7 @@ class ObjectImportCommand extends Command
|
||||
$this->progressIndicator = new ProgressIndicator($this->output);
|
||||
|
||||
$filename = $this->argument('filename');
|
||||
$class = title_case($this->option('item-type'));
|
||||
$class = ucfirst($this->option('item-type'));
|
||||
$classString = "App\\Importer\\{$class}Importer";
|
||||
$importer = new $classString($filename);
|
||||
$importer->setCallbacks([$this, 'log'], [$this, 'progress'], [$this, 'errorCallback'])
|
||||
|
||||
@@ -49,14 +49,15 @@ class ResetDemoSettings extends Command
|
||||
$settings->logo = 'snipe-logo.png';
|
||||
$settings->alert_email = 'service@snipe-it.io';
|
||||
$settings->login_note = 'Use `admin` / `password` to login to the demo.';
|
||||
$settings->header_color = null;
|
||||
$settings->header_color = '#3c8dbc';
|
||||
$settings->link_dark_color = '#86cbf2';
|
||||
$settings->link_light_color = '#084d73;';
|
||||
$settings->label2_2d_type = 'QRCODE';
|
||||
$settings->default_currency = 'USD';
|
||||
$settings->brand = 2;
|
||||
$settings->ldap_enabled = 0;
|
||||
$settings->full_multiple_companies_support = 0;
|
||||
$settings->label2_1d_type = 'C128';
|
||||
$settings->skin = '';
|
||||
$settings->email_domain = 'snipeitapp.com';
|
||||
$settings->email_format = 'filastname';
|
||||
$settings->username_format = 'filastname';
|
||||
@@ -80,6 +81,8 @@ class ResetDemoSettings extends Command
|
||||
|
||||
if ($user = User::where('username', '=', 'admin')->first()) {
|
||||
$user->locale = 'en-US';
|
||||
$user->enable_confetti = 1;
|
||||
$user->enable_sounds = 1;
|
||||
$user->save();
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class SQLStreamer {
|
||||
/* we *could* have made the ^INSERT INTO blah VALUES$ turn on the capturing state, and closed it with
|
||||
a ^(blahblah);$ but it's cleaner to not have to manage the state machine. We're just going to
|
||||
assume that (blahblah), or (blahblah); are values for INSERT and are always acceptable. */
|
||||
"<^/\*!40101 SET NAMES '?[a-zA-Z0-9_-]+'? \*/;$>" => false, //using weird delimiters (<,>) for readability. allow quoted or unquoted charsets
|
||||
"<^/\*![0-9]{5} SET NAMES '?[a-zA-Z0-9_-]+'? \*/;$>" => false, //using weird delimiters (<,>) for readability. allow quoted or unquoted charsets
|
||||
"<^/\*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' \*/;$>" => false, //same, now handle zero-values
|
||||
];
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ use Illuminate\Support\Facades\Mail;
|
||||
class SendExpirationAlerts extends Command
|
||||
{
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'snipeit:expiring-alerts';
|
||||
protected $signature = 'snipeit:expiring-alerts {--expired-licenses}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@@ -85,7 +85,7 @@ class SendExpirationAlerts extends Command
|
||||
}
|
||||
|
||||
// Expiring licenses
|
||||
$licenses = License::query()->ExpiringLicenses($alert_interval)
|
||||
$licenses = License::query()->ExpiringLicenses($alert_interval, $this->option('expired-licenses'))
|
||||
->with('manufacturer','category')
|
||||
->orderBy('expiration_date', 'ASC')
|
||||
->orderBy('termination_date', 'ASC')
|
||||
|
||||
@@ -784,7 +784,7 @@ class Helper
|
||||
|
||||
foreach ($consumables as $consumable) {
|
||||
$avail = $consumable->numRemaining();
|
||||
if ($avail < ($consumable->min_amt) + $alert_threshold) {
|
||||
if ($avail <= ($consumable->min_amt) + $alert_threshold) {
|
||||
if ($consumable->qty > 0) {
|
||||
$percent = number_format((($avail / $consumable->qty) * 100), 0);
|
||||
} else {
|
||||
@@ -803,7 +803,7 @@ class Helper
|
||||
|
||||
foreach ($accessories as $accessory) {
|
||||
$avail = $accessory->qty - $accessory->checkouts_count;
|
||||
if ($avail < ($accessory->min_amt) + $alert_threshold) {
|
||||
if ($avail <= ($accessory->min_amt) + $alert_threshold) {
|
||||
if ($accessory->qty > 0) {
|
||||
$percent = number_format((($avail / $accessory->qty) * 100), 0);
|
||||
} else {
|
||||
@@ -822,7 +822,7 @@ class Helper
|
||||
|
||||
foreach ($components as $component) {
|
||||
$avail = $component->numRemaining();
|
||||
if ($avail < ($component->min_amt) + $alert_threshold) {
|
||||
if ($avail <= ($component->min_amt) + $alert_threshold) {
|
||||
if ($component->qty > 0) {
|
||||
$percent = number_format((($avail / $component->qty) * 100), 0);
|
||||
} else {
|
||||
@@ -845,7 +845,7 @@ class Helper
|
||||
$total_owned = $asset->where('model_id', '=', $asset_model->id)->count();
|
||||
$avail = $asset->where('model_id', '=', $asset_model->id)->whereNull('assigned_to')->count();
|
||||
|
||||
if ($avail < ($asset_model->min_amt) + $alert_threshold) {
|
||||
if ($avail <= ($asset_model->min_amt) + $alert_threshold) {
|
||||
if ($avail > 0) {
|
||||
$percent = number_format((($avail / $total_owned) * 100), 0);
|
||||
} else {
|
||||
@@ -863,7 +863,7 @@ class Helper
|
||||
|
||||
foreach ($licenses as $license){
|
||||
$avail = $license->remaincount();
|
||||
if ($avail < ($license->min_amt) + $alert_threshold) {
|
||||
if ($avail <= ($license->min_amt) + $alert_threshold) {
|
||||
if ($avail > 0) {
|
||||
$percent = number_format((($avail / $license->min_amt) * 100), 0);
|
||||
} else {
|
||||
|
||||
@@ -216,7 +216,7 @@ class AcceptanceController extends Controller
|
||||
try {
|
||||
$recipient = User::find($acceptance->alert_on_response_id);
|
||||
|
||||
if ($recipient) {
|
||||
if ($recipient?->email) {
|
||||
Log::debug('Attempting to send email acceptance.');
|
||||
Mail::to($recipient)->send(new CheckoutAcceptanceResponseMail(
|
||||
$acceptance,
|
||||
|
||||
@@ -58,8 +58,8 @@ class ComponentsController extends Controller
|
||||
];
|
||||
|
||||
$components = Component::select('components.*')
|
||||
->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer', 'uncontrainedAssets')
|
||||
->withSum('uncontrainedAssets', 'components_assets.assigned_qty');
|
||||
->with('company', 'location', 'category', 'supplier', 'adminuser', 'manufacturer')
|
||||
->withSum('uncontrainedAssets as sum_unconstrained_assets', 'components_assets.assigned_qty');
|
||||
|
||||
$filter = [];
|
||||
|
||||
@@ -112,7 +112,8 @@ class ComponentsController extends Controller
|
||||
}
|
||||
|
||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||
$offset = ($request->input('offset') > $components->count()) ? $components->count() : app('api_offset_value');
|
||||
$components_count = $components->count();
|
||||
$offset = ($request->input('offset') > $components_count) ? $components_count : app('api_offset_value');
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
@@ -143,7 +144,7 @@ class ComponentsController extends Controller
|
||||
break;
|
||||
}
|
||||
|
||||
$total = $components->count();
|
||||
$total = $components_count;
|
||||
$components = $components->skip($offset)->take($limit)->get();
|
||||
|
||||
return (new ComponentsTransformer)->transformComponents($components, $total);
|
||||
|
||||
@@ -15,6 +15,7 @@ use Illuminate\Database\Eloquent\JsonEncodingException;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use League\Csv\Reader;
|
||||
use Onnov\DetectEncoding\EncodingDetector;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||
@@ -149,7 +150,9 @@ class ImportController extends Controller
|
||||
}
|
||||
|
||||
$date = date('Y-m-d-his');
|
||||
$fixed_filename = str_slug($file->getClientOriginalName());
|
||||
|
||||
$fixed_filename = Str::of($file->getClientOriginalName())->basename('.csv').'.csv';
|
||||
|
||||
try {
|
||||
$file->move($path, $date.'-'.$fixed_filename);
|
||||
} catch (FileException $exception) {
|
||||
@@ -211,36 +214,47 @@ class ImportController extends Controller
|
||||
$redirectTo = 'hardware.index';
|
||||
switch ($request->get('import-type')) {
|
||||
case 'asset':
|
||||
$model_perms = 'App\Models\Asset';
|
||||
$redirectTo = 'hardware.index';
|
||||
break;
|
||||
case 'assetModel':
|
||||
$model_perms = 'App\Models\AssetModel';
|
||||
$redirectTo = 'models.index';
|
||||
break;
|
||||
case 'accessory':
|
||||
$model_perms = 'App\Models\Accessory';
|
||||
$redirectTo = 'accessories.index';
|
||||
break;
|
||||
case 'consumable':
|
||||
$model_perms = 'App\Models\Consumable';
|
||||
$redirectTo = 'consumables.index';
|
||||
break;
|
||||
case 'component':
|
||||
$model_perms = 'App\Models\Component';
|
||||
$redirectTo = 'components.index';
|
||||
break;
|
||||
case 'license':
|
||||
$model_perms = 'App\Models\License';
|
||||
$redirectTo = 'licenses.index';
|
||||
break;
|
||||
case 'user':
|
||||
$model_perms = 'App\Models\User';
|
||||
$redirectTo = 'users.index';
|
||||
break;
|
||||
case 'location':
|
||||
$model_perms = 'App\Models\Location';
|
||||
$redirectTo = 'locations.index';
|
||||
break;
|
||||
case 'supplier':
|
||||
$model_perms = 'App\Models\Supplier';
|
||||
$redirectTo = 'suppliers.index';
|
||||
break;
|
||||
case 'manufacturer':
|
||||
$model_perms = 'App\Models\Manufacturer';
|
||||
$redirectTo = 'manufacturers.index';
|
||||
break;
|
||||
case 'category':
|
||||
$model_perms = 'App\Models\Category';
|
||||
$redirectTo = 'categories.index';
|
||||
break;
|
||||
}
|
||||
@@ -251,7 +265,11 @@ class ImportController extends Controller
|
||||
//Flash message before the redirect
|
||||
Session::flash('success', trans('admin/hardware/message.import.success'));
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route($redirectTo)]));
|
||||
if (auth()->user()->can('view', $model_perms)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route($redirectTo)]));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route('imports.index')]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,9 +279,16 @@ class ImportController extends Controller
|
||||
*/
|
||||
public function destroy($import_id) : JsonResponse
|
||||
{
|
||||
$this->authorize('create', Asset::class);
|
||||
$this->authorize('import');
|
||||
|
||||
if ($import = Import::find($import_id)) {
|
||||
|
||||
|
||||
if ((auth()->user()->id != $import->created_by) && (!auth()->user()->isSuperUser())) {
|
||||
return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning')));
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// Try to delete the file
|
||||
Storage::delete('imports/'.$import->file_path);
|
||||
@@ -280,4 +305,6 @@ class ImportController extends Controller
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning')));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -242,6 +242,7 @@ class LocationsController extends Controller
|
||||
'locations.currency',
|
||||
'locations.company_id',
|
||||
'locations.notes',
|
||||
'locations.tag_color',
|
||||
])
|
||||
->withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assets as assets_count')
|
||||
|
||||
@@ -78,10 +78,16 @@ class ManufacturersController extends Controller
|
||||
$manufacturers->onlyTrashed();
|
||||
}
|
||||
|
||||
if ($request->input('status') == 'deleted') {
|
||||
$manufacturers->onlyTrashed();
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$manufacturers = $manufacturers->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($request->filled('name')) {
|
||||
$manufacturers->where('name', '=', $request->input('name'));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use Laravel\Passport\TokenRepository;
|
||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
@@ -179,10 +180,17 @@ class ProfileController extends Controller
|
||||
*@since [v8.1.16]
|
||||
* @author [Godfrey Martinez] [<gmartinez@grokability.com>]
|
||||
*/
|
||||
public function eulas(ProfileTransformer $transformer)
|
||||
public function eulas(ProfileTransformer $transformer, Request $request)
|
||||
{
|
||||
// Only return this user's EULAs
|
||||
$eulas = auth()->user()->eulas;
|
||||
if($request->filled('user_id') && $request->input('user_id') != 0) {
|
||||
// Return selected user's EULAs
|
||||
$eulas = User::find($request->input('user_id'))->eulas;
|
||||
}
|
||||
else {
|
||||
// Only return this user's EULAs
|
||||
$eulas = auth()->user()->eulas;
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$transformer->transformFiles($eulas, $eulas->count())
|
||||
);
|
||||
|
||||
@@ -522,93 +522,99 @@ class UsersController extends Controller
|
||||
{
|
||||
$this->authorize('update', User::class);
|
||||
|
||||
$this->authorize('update', $user);
|
||||
$this->authorize('update', $user);
|
||||
|
||||
/**
|
||||
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
|
||||
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
|
||||
* Thanks, jerks. You are why we can't have nice things. - snipe
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* This is a janky hack to prevent people from changing admin demo user data on the public demo.
|
||||
* The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
|
||||
* Thanks, jerks. You are why we can't have nice things. - snipe
|
||||
*
|
||||
*/
|
||||
|
||||
if ((($user->id == 1) || ($user->id == 2)) && (config('app.lock_passwords'))) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Permission denied. You cannot update user information via API on the demo.'));
|
||||
}
|
||||
|
||||
// Pull out sensitive fields that require extra permission
|
||||
$user->fill($request->except(['password', 'username', 'email', 'activated', 'permissions', 'activation_code', 'remember_token', 'two_factor_secret', 'two_factor_enrolled', 'two_factor_optin']));
|
||||
|
||||
|
||||
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
|
||||
$user->fill($request->all());
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$user->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
if ($request->filled('username')) {
|
||||
$user->username = $request->input('username');
|
||||
}
|
||||
|
||||
if ($user->id == $request->input('manager_id')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
|
||||
if ($request->filled('email')) {
|
||||
$user->email = $request->input('email');
|
||||
}
|
||||
|
||||
// check for permissions related fields and pull them out if the current user cannot edit them
|
||||
if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
|
||||
if ($request->filled('username')) {
|
||||
$user->username = $request->input('username');
|
||||
}
|
||||
|
||||
if ($request->filled('display_name')) {
|
||||
$user->display_name = $request->input('display_name');
|
||||
}
|
||||
|
||||
if ($request->filled('email')) {
|
||||
$user->email = $request->input('email');
|
||||
}
|
||||
|
||||
if ($request->filled('activated')) {
|
||||
$user->activated = $request->input('activated');
|
||||
}
|
||||
|
||||
if ($request->filled('activated')) {
|
||||
$user->activated = $request->input('activated');
|
||||
}
|
||||
|
||||
// We need to use has() instead of filled()
|
||||
// here because we need to overwrite permissions
|
||||
// if someone needs to null them out
|
||||
if ($request->has('permissions')) {
|
||||
$permissions_array = $request->input('permissions');
|
||||
}
|
||||
|
||||
// Strip out the individual superuser permission if the API user isn't a superadmin
|
||||
if (!auth()->user()->isSuperUser()) {
|
||||
unset($permissions_array['superuser']);
|
||||
// We need to use has() instead of filled()
|
||||
// here because we need to overwrite permissions
|
||||
// if someone needs to null them out
|
||||
|
||||
if ($request->filled('display_name')) {
|
||||
$user->display_name = $request->input('display_name');
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$user->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
}
|
||||
|
||||
if ($user->id == $request->input('manager_id')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($request->has('permissions')) {
|
||||
$permissions_array = $request->input('permissions');
|
||||
|
||||
// Strip out the individual superuser permission if the API user isn't a superadmin
|
||||
if (!auth()->user()->isSuperUser()) {
|
||||
unset($permissions_array['superuser']);
|
||||
}
|
||||
|
||||
$user->permissions = $permissions_array;
|
||||
}
|
||||
|
||||
if ($request->has('location_id')) {
|
||||
// Update the location of any assets checked out to this user
|
||||
Asset::where('assigned_type', User::class)
|
||||
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
||||
}
|
||||
|
||||
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
if ($user->save()) {
|
||||
// Check if the request has groups passed and has a value, AND that the user us a superuser
|
||||
if (($request->has('groups')) && (auth()->user()->isSuperUser())) {
|
||||
|
||||
$validator = Validator::make($request->only('groups'), [
|
||||
'groups.*' => 'integer|exists:permission_groups,id',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
|
||||
}
|
||||
|
||||
$user->permissions = $permissions_array;
|
||||
// Sync the groups since the user is a superuser and the groups pass validation
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
}
|
||||
|
||||
if($request->has('location_id')) {
|
||||
// Update the location of any assets checked out to this user
|
||||
Asset::where('assigned_type', User::class)
|
||||
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
||||
}
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
if ($user->save()) {
|
||||
// Check if the request has groups passed and has a value, AND that the user us a superuser
|
||||
if (($request->has('groups')) && (auth()->user()->isSuperUser())) {
|
||||
|
||||
$validator = Validator::make($request->only('groups'), [
|
||||
'groups.*' => 'integer|exists:permission_groups,id',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()));
|
||||
}
|
||||
|
||||
// Sync the groups since the user is a superuser and the groups pass validation
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $user->getErrors()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Events\CheckoutableCheckedIn;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Requests\CreateMultipleAssetRequest;
|
||||
use App\Http\Requests\UpdateAssetRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
@@ -98,7 +99,7 @@ class AssetsController extends Controller
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function store(ImageUploadRequest $request) : RedirectResponse
|
||||
public function store(CreateMultipleAssetRequest $request): RedirectResponse
|
||||
{
|
||||
$this->authorize(Asset::class);
|
||||
|
||||
@@ -135,122 +136,136 @@ class AssetsController extends Controller
|
||||
$successes = [];
|
||||
$failures = [];
|
||||
|
||||
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
|
||||
$asset = new Asset();
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
|
||||
$asset = new Asset();
|
||||
|
||||
$asset->model()->associate($model);
|
||||
$asset->name = $request->input('name');
|
||||
$asset->model()->associate($model);
|
||||
$asset->name = $request->input('name');
|
||||
|
||||
// Check for a corresponding serial
|
||||
if (($serials) && (array_key_exists($a, $serials))) {
|
||||
$asset->serial = $serials[$a];
|
||||
}
|
||||
|
||||
if (($asset_tags) && (array_key_exists($a, $asset_tags))) {
|
||||
$asset->asset_tag = $asset_tags[$a];
|
||||
}
|
||||
|
||||
$asset->company_id = $companyId;
|
||||
$asset->model_id = $request->input('model_id');
|
||||
$asset->order_number = $request->input('order_number');
|
||||
$asset->notes = $request->input('notes');
|
||||
$asset->created_by = auth()->id();
|
||||
$asset->status_id = request('status_id');
|
||||
$asset->warranty_months = request('warranty_months', null);
|
||||
$asset->purchase_cost = request('purchase_cost');
|
||||
$asset->purchase_date = request('purchase_date', null);
|
||||
$asset->asset_eol_date = request('asset_eol_date', null);
|
||||
$asset->assigned_to = request('assigned_to', null);
|
||||
$asset->supplier_id = request('supplier_id', null);
|
||||
$asset->requestable = request('requestable', 0);
|
||||
$asset->rtd_location_id = request('rtd_location_id', null);
|
||||
$asset->byod = request('byod', 0);
|
||||
|
||||
if (! empty($settings->audit_interval)) {
|
||||
$asset->next_audit_date = Carbon::now()->addMonths((int) $settings->audit_interval)->toDateString();
|
||||
}
|
||||
|
||||
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
|
||||
if (!request('assigned_user') && !request('assigned_asset') && !request('assigned_location')) {
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
}
|
||||
|
||||
if ($request->has('use_cloned_image')) {
|
||||
$cloned_model_img = Asset::select('image')->find($request->input('clone_image_from_id'));
|
||||
if ($cloned_model_img) {
|
||||
$new_image_name = 'clone-'.date('U').'-'.$cloned_model_img->image;
|
||||
$new_image = 'assets/'.$new_image_name;
|
||||
Storage::disk('public')->copy('assets/'.$cloned_model_img->image, $new_image);
|
||||
$asset->image = $new_image_name;
|
||||
// Check for a corresponding serial
|
||||
if (($serials) && (array_key_exists($a, $serials))) {
|
||||
$asset->serial = $serials[$a];
|
||||
}
|
||||
|
||||
} else {
|
||||
$asset = $request->handleImages($asset);
|
||||
}
|
||||
if (($asset_tags) && (array_key_exists($a, $asset_tags))) {
|
||||
$asset->asset_tag = $asset_tags[$a];
|
||||
}
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
$asset->company_id = $companyId;
|
||||
$asset->model_id = $request->input('model_id');
|
||||
$asset->order_number = $request->input('order_number');
|
||||
$asset->notes = $request->input('notes');
|
||||
$asset->created_by = auth()->id();
|
||||
$asset->status_id = request('status_id');
|
||||
$asset->warranty_months = request('warranty_months', null);
|
||||
$asset->purchase_cost = request('purchase_cost');
|
||||
$asset->purchase_date = request('purchase_date', null);
|
||||
$asset->asset_eol_date = request('asset_eol_date', null);
|
||||
$asset->assigned_to = request('assigned_to', null);
|
||||
$asset->supplier_id = request('supplier_id', null);
|
||||
$asset->requestable = request('requestable', 0);
|
||||
$asset->rtd_location_id = request('rtd_location_id', null);
|
||||
$asset->byod = request('byod', 0);
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
if (!empty($settings->audit_interval)) {
|
||||
$asset->next_audit_date = Carbon::now()->addMonths((int)$settings->audit_interval)->toDateString();
|
||||
}
|
||||
|
||||
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
|
||||
if (!request('assigned_user') && !request('assigned_asset') && !request('assigned_location')) {
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
}
|
||||
|
||||
if ($request->has('use_cloned_image')) {
|
||||
$cloned_model_img = Asset::select('image')->find($request->input('clone_image_from_id'));
|
||||
if ($cloned_model_img) {
|
||||
$new_image_name = 'clone-' . date('U') . '-' . $cloned_model_img->image;
|
||||
$new_image = 'assets/' . $new_image_name;
|
||||
Storage::disk('public')->copy('assets/' . $cloned_model_img->image, $new_image);
|
||||
$asset->image = $new_image_name;
|
||||
}
|
||||
|
||||
} else {
|
||||
$asset = $request->handleImages($asset);
|
||||
}
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the asset before saving
|
||||
// Note - it can be tempting to instead want to call saveOrFail(), to automatically throw when an object
|
||||
// is invalid (and can't save). But this won't work, because Custom Fields _overrides_ the save() method
|
||||
// to inject the Custom Field Rules into the $rules property right before invoking the _real_ save.
|
||||
// so, instead, we have to catch failures on the 'else' clause and throw there.
|
||||
if ($asset->isValid() && $asset->save()) {
|
||||
$target = null;
|
||||
$location = null;
|
||||
|
||||
if ($userId = request('assigned_user')) {
|
||||
$target = User::find($userId);
|
||||
|
||||
if (!$target) {
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.user'));
|
||||
}
|
||||
$location = $target->location_id;
|
||||
|
||||
} elseif ($assetId = request('assigned_asset')) {
|
||||
$target = Asset::find($assetId);
|
||||
|
||||
if (!$target) {
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.asset'));
|
||||
}
|
||||
$location = $target->location_id;
|
||||
|
||||
} elseif ($locationId = request('assigned_location')) {
|
||||
$target = Location::find($locationId);
|
||||
|
||||
if (!$target) {
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.location'));
|
||||
}
|
||||
$location = $target->id;
|
||||
}
|
||||
|
||||
if (isset($target)) {
|
||||
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
|
||||
}
|
||||
|
||||
$successes[] = "<a href='" . route('hardware.show', $asset) . "' style='color: white;'>" . e($asset->asset_tag) . "</a>";
|
||||
|
||||
} else {
|
||||
$asset->throwValidationException(); // we have to do this for the reason listed above - can't use saveOrFail()
|
||||
$failures[] = join(",", $asset->getErrors()->all()); //TODO - this can probably go away soon
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the asset before saving
|
||||
if ($asset->isValid() && $asset->save()) {
|
||||
$target = null;
|
||||
$location = null;
|
||||
|
||||
if ($userId = request('assigned_user')) {
|
||||
$target = User::find($userId);
|
||||
|
||||
if (!$target) {
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.user'));
|
||||
}
|
||||
$location = $target->location_id;
|
||||
|
||||
} elseif ($assetId = request('assigned_asset')) {
|
||||
$target = Asset::find($assetId);
|
||||
|
||||
if (!$target) {
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.asset'));
|
||||
}
|
||||
$location = $target->location_id;
|
||||
|
||||
} elseif ($locationId = request('assigned_location')) {
|
||||
$target = Location::find($locationId);
|
||||
|
||||
if (!$target) {
|
||||
return redirect()->back()->withInput()->with('error', trans('admin/hardware/message.create.target_not_found.location'));
|
||||
}
|
||||
$location = $target->id;
|
||||
}
|
||||
|
||||
if (isset($target)) {
|
||||
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
|
||||
}
|
||||
|
||||
$successes[] = "<a href='" . route('hardware.show', $asset) . "' style='color: white;'>" . e($asset->asset_tag) . "</a>";
|
||||
|
||||
} else {
|
||||
$failures[] = join(",", $asset->getErrors()->all());
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
\Log::debug("Caught exception in multi-create - rolling back: " . $e->getMessage());
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
DB::commit();
|
||||
|
||||
if($request->get('redirect_option') === 'back'){
|
||||
session()->put(['redirect_option' => 'index']);
|
||||
} else {
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Transformers\ProfileTransformer;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CurrentInventory;
|
||||
@@ -34,7 +35,7 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function getIndex() : View
|
||||
{
|
||||
$this->authorize('self.profile');
|
||||
|
||||
$user = auth()->user();
|
||||
return view('account/profile', compact('user'));
|
||||
}
|
||||
@@ -47,20 +48,25 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function postIndex(ImageUploadRequest $request) : RedirectResponse
|
||||
{
|
||||
$this->authorize('self.profile');
|
||||
|
||||
$user = auth()->user();
|
||||
$user->first_name = $request->input('first_name');
|
||||
$user->last_name = $request->input('last_name');
|
||||
$user->website = $request->input('website');
|
||||
$user->gravatar = $request->input('gravatar');
|
||||
$user->skin = $request->input('skin');
|
||||
$user->phone = $request->input('phone');
|
||||
|
||||
if ((Gate::allows('self.profile')) && (! config('app.lock_passwords'))) {
|
||||
$user->first_name = $request->input('first_name');
|
||||
$user->last_name = $request->input('last_name');
|
||||
$user->website = $request->input('website');
|
||||
$user->gravatar = $request->input('gravatar');
|
||||
$user->phone = $request->input('phone');
|
||||
}
|
||||
|
||||
|
||||
$user->enable_sounds = $request->input('enable_sounds', false);
|
||||
$user->enable_confetti = $request->input('enable_confetti', false);
|
||||
$user->link_light_color = $request->input('link_light_color', '#296282');
|
||||
$user->link_dark_color = $request->input('link_dark_color', '#296282');
|
||||
$user->nav_link_color = $request->input('nav_link_color', '#FFFFFF');
|
||||
$user->locale = $request->input('locale');
|
||||
|
||||
if (! config('app.lock_passwords')) {
|
||||
$user->locale = $request->input('locale');
|
||||
}
|
||||
|
||||
if ((Gate::allows('self.two_factor')) && ((Setting::getSettings()->two_factor_enabled == '1') && (! config('app.lock_passwords')))) {
|
||||
$user->two_factor_optin = $request->input('two_factor_optin', '0');
|
||||
@@ -249,7 +255,10 @@ class ProfileController extends Controller
|
||||
$logentry = Actionlog::where('filename', $filename)->first();
|
||||
|
||||
// Make sure the user has permission to view this file
|
||||
if (auth()->id() != $logentry->target_id) {
|
||||
// Also allow if the user (manager) able to view both users and assets
|
||||
$allowed_to_view_users_assets = Gate::allows('view', User::class) && Gate::allows('view', Asset::class);
|
||||
|
||||
if (auth()->id() != $logentry->target_id && !$allowed_to_view_users_assets) {
|
||||
return redirect()->route('account')->with('error', trans('general.generic_model_not_found', ['model' => 'file']));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,38 +6,31 @@ use App\Helpers\Helper;
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Requests\SettingsSamlRequest;
|
||||
use App\Http\Requests\SetupUserRequest;
|
||||
use App\Http\Requests\StoreLabelSettings;
|
||||
use App\Http\Requests\StoreLdapSettings;
|
||||
use App\Http\Requests\StoreLocalizationSettings;
|
||||
use App\Http\Requests\StoreNotificationSettings;
|
||||
use App\Http\Requests\StoreLabelSettings;
|
||||
use App\Http\Requests\StoreSecuritySettings;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\Group;
|
||||
use App\Models\Labels\Label as LabelModel;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Asset;
|
||||
use App\Models\User;
|
||||
use App\Notifications\FirstAdminNotification;
|
||||
use App\Notifications\MailTest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Settings for
|
||||
@@ -47,224 +40,6 @@ use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
*/
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Checks to see whether or not the database has a migrations table
|
||||
* and a user, otherwise display the setup view.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v3.0]
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View | \Illuminate\Http\Response
|
||||
*/
|
||||
public function getSetupIndex() : View
|
||||
{
|
||||
$start_settings['php_version_min'] = false;
|
||||
|
||||
if (version_compare(PHP_VERSION, config('app.min_php'), '<')) {
|
||||
return response('<center><h1>This software requires PHP version '.config('app.min_php').' or greater. This server is running '.PHP_VERSION.'. </h1><h2>Please upgrade PHP on this server and try again. </h2></center>', 500);
|
||||
}
|
||||
|
||||
try {
|
||||
$conn = DB::select('select 2 + 2');
|
||||
$start_settings['db_conn'] = true;
|
||||
$start_settings['db_name'] = DB::connection()->getDatabaseName();
|
||||
$start_settings['db_error'] = null;
|
||||
} catch (\PDOException $e) {
|
||||
$start_settings['db_conn'] = false;
|
||||
$start_settings['db_name'] = config('database.connections.mysql.database');
|
||||
$start_settings['db_error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$start_settings['url_config'] = trim(config('app.url'), '/'). '/setup';
|
||||
$start_settings['real_url'] = request()->url();
|
||||
$start_settings['url_valid'] = $start_settings['url_config'] === $start_settings['real_url'];
|
||||
$start_settings['php_version_min'] = true;
|
||||
|
||||
// Curl the .env file to make sure it's not accessible via a browser
|
||||
$start_settings['env_exposed'] = $this->dotEnvFileIsExposed();
|
||||
|
||||
if (App::Environment('production') && (true == config('app.debug'))) {
|
||||
$start_settings['debug_exposed'] = true;
|
||||
} else {
|
||||
$start_settings['debug_exposed'] = false;
|
||||
}
|
||||
|
||||
$environment = app()->environment();
|
||||
if ('production' != $environment) {
|
||||
$start_settings['env'] = $environment;
|
||||
$start_settings['prod'] = false;
|
||||
} else {
|
||||
$start_settings['env'] = $environment;
|
||||
$start_settings['prod'] = true;
|
||||
}
|
||||
|
||||
$start_settings['owner'] = '';
|
||||
|
||||
if (function_exists('posix_getpwuid')) { // Probably Linux
|
||||
$owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME']));
|
||||
// This *should* be an array, but we've seen this return a bool in some chrooted environments
|
||||
if (is_array($owner)) {
|
||||
$start_settings['owner'] = $owner['name'];
|
||||
}
|
||||
}
|
||||
|
||||
if (($start_settings['owner'] === 'root') || ($start_settings['owner'] === '0')) {
|
||||
$start_settings['owner_is_admin'] = true;
|
||||
} else {
|
||||
$start_settings['owner_is_admin'] = false;
|
||||
}
|
||||
|
||||
$start_settings['writable'] = $this->storagePathIsWritable();
|
||||
|
||||
$start_settings['gd'] = extension_loaded('gd');
|
||||
|
||||
return view('setup/index')
|
||||
->with('step', 1)
|
||||
->with('start_settings', $start_settings)
|
||||
->with('section', 'Pre-Flight Check');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the .env file accessible via a browser.
|
||||
*
|
||||
* @return bool This method will return true when exceptions (such as curl exception) is thrown.
|
||||
* Check the log files to see more details about the exception.
|
||||
*/
|
||||
protected function dotEnvFileIsExposed() : bool
|
||||
{
|
||||
try {
|
||||
return Http::withoutVerifying()->timeout(10)
|
||||
->accept('*/*')
|
||||
->get(URL::to('.env'))
|
||||
->successful();
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e->getMessage());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the app storage path is writable.
|
||||
*/
|
||||
protected function storagePathIsWritable(): bool
|
||||
{
|
||||
return File::isWritable(storage_path()) &&
|
||||
File::isWritable(storage_path('framework')) &&
|
||||
File::isWritable(storage_path('framework/cache')) &&
|
||||
File::isWritable(storage_path('framework/sessions')) &&
|
||||
File::isWritable(storage_path('framework/views')) &&
|
||||
File::isWritable(storage_path('logs'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the first admin user from Setup.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
*
|
||||
*/
|
||||
public function postSaveFirstAdmin(SetupUserRequest $request) : RedirectResponse
|
||||
{
|
||||
|
||||
$user = new User();
|
||||
$user->first_name = $data['first_name'] = $request->input('first_name');
|
||||
$user->last_name = $request->input('last_name');
|
||||
$user->email = $data['email'] = $request->input('email');
|
||||
$user->activated = 1;
|
||||
$permissions = ['superuser' => 1];
|
||||
$user->permissions = json_encode($permissions);
|
||||
$user->username = $data['username'] = $request->input('username');
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
$data['password'] = $request->input('password');
|
||||
|
||||
$settings = new Setting();
|
||||
$settings->full_multiple_companies_support = $request->input('full_multiple_companies_support', 0);
|
||||
$settings->site_name = $request->input('site_name');
|
||||
$settings->alert_email = $request->input('email');
|
||||
$settings->alerts_enabled = 1;
|
||||
$settings->pwd_secure_min = 10;
|
||||
$settings->brand = 1;
|
||||
$settings->locale = $request->input('locale', 'en-US');
|
||||
$settings->default_currency = $request->input('default_currency', 'USD');
|
||||
$settings->created_by = 1;
|
||||
$settings->email_domain = $request->input('email_domain');
|
||||
$settings->email_format = $request->input('email_format');
|
||||
$settings->next_auto_tag_base = 1;
|
||||
$settings->auto_increment_assets = $request->input('auto_increment_assets', 0);
|
||||
$settings->auto_increment_prefix = $request->input('auto_increment_prefix');
|
||||
$settings->zerofill_count = $request->input('zerofill_count') ?: 0;
|
||||
|
||||
if ((! $user->isValid()) || (! $settings->isValid())) {
|
||||
return redirect()->back()->withInput()->withErrors($user->getErrors())->withErrors($settings->getErrors());
|
||||
} else {
|
||||
$user->save();
|
||||
Auth::login($user, true);
|
||||
$settings->save();
|
||||
|
||||
if ($request->input('email_creds') == '1') {
|
||||
$data = [];
|
||||
$data['email'] = $user->email;
|
||||
$data['username'] = $user->username;
|
||||
$data['first_name'] = $user->first_name;
|
||||
$data['last_name'] = $user->last_name;
|
||||
$data['password'] = $request->input('password');
|
||||
$user->notify(new FirstAdminNotification($data));
|
||||
}
|
||||
|
||||
return redirect()->route('setup.done');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the admin user creation form in Setup.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v3.0]
|
||||
*/
|
||||
public function getSetupUser() : View
|
||||
{
|
||||
return view('setup/user')
|
||||
->with('step', 3)
|
||||
->with('section', 'Create a User');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the view that tells the user that the Setup is done.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v3.0]
|
||||
*/
|
||||
public function getSetupDone() : View
|
||||
{
|
||||
return view('setup/done')
|
||||
->with('step', 4)
|
||||
->with('section', 'Done!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate the database tables, and return the output
|
||||
* to a view for Setup.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v3.0]
|
||||
*/
|
||||
public function getSetupMigrate() : View
|
||||
{
|
||||
Artisan::call('migrate', ['--force' => true]);
|
||||
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
|
||||
Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]);
|
||||
Artisan::call('passport:install', ['--no-interaction' => true]);
|
||||
}
|
||||
|
||||
return view('setup/migrate')
|
||||
->with('output', 'Databases installed!')
|
||||
->with('step', 2)
|
||||
->with('section', 'Create Database Tables');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a view that shows some of the key settings.
|
||||
@@ -399,12 +174,10 @@ class SettingsController extends Controller
|
||||
}
|
||||
|
||||
$setting->brand = $request->input('brand', '1');
|
||||
$setting->header_color = $request->input('header_color');
|
||||
|
||||
$setting->support_footer = $request->input('support_footer');
|
||||
$setting->version_footer = $request->input('version_footer');
|
||||
$setting->footer_text = $request->input('footer_text');
|
||||
$setting->skin = $request->input('skin');
|
||||
$setting->allow_user_skin = $request->input('allow_user_skin', '0');
|
||||
$setting->show_url_in_emails = $request->input('show_url_in_emails', '0');
|
||||
$setting->logo_print_assets = $request->input('logo_print_assets', '0');
|
||||
$setting->load_remote = $request->input('load_remote', 0);
|
||||
@@ -418,6 +191,11 @@ class SettingsController extends Controller
|
||||
$request->validate(['site_name' => 'required']);
|
||||
}
|
||||
|
||||
$setting->header_color = $request->input('header_color');
|
||||
$setting->link_light_color = $request->input('link_light_color', '#296282');
|
||||
$setting->link_dark_color = $request->input('link_dark_color', '#296282');
|
||||
$setting->nav_link_color = $request->input('nav_link_color', '#FFFFFF');
|
||||
|
||||
$setting->site_name = $request->input('site_name', 'Snipe-IT');
|
||||
$setting->custom_css = $request->input('custom_css');
|
||||
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\SetupUserRequest;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Notifications\FirstAdminNotification;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Settings for
|
||||
* the Snipe-IT Asset Management application.
|
||||
*
|
||||
* @version v1.0
|
||||
*/
|
||||
class SetupController extends Controller
|
||||
{
|
||||
/**
|
||||
* Checks to see whether or not the database has a migrations table
|
||||
* and a user, otherwise display the setup view.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v3.0]
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View | \Illuminate\Http\Response
|
||||
*/
|
||||
public function getSetupIndex() : View
|
||||
{
|
||||
$start_settings['php_version_min'] = false;
|
||||
|
||||
if (version_compare(PHP_VERSION, config('app.min_php'), '<')) {
|
||||
return response('<center><h1>This software requires PHP version '.config('app.min_php').' or greater. This server is running '.PHP_VERSION.'. </h1><h2>Please upgrade PHP on this server and try again. </h2></center>', 500);
|
||||
}
|
||||
|
||||
try {
|
||||
$conn = DB::select('select 2 + 2');
|
||||
$start_settings['db_conn'] = true;
|
||||
$start_settings['db_name'] = DB::connection()->getDatabaseName();
|
||||
$start_settings['db_error'] = null;
|
||||
} catch (\PDOException $e) {
|
||||
$start_settings['db_conn'] = false;
|
||||
$start_settings['db_name'] = config('database.connections.mysql.database');
|
||||
$start_settings['db_error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$start_settings['url_config'] = trim(config('app.url'), '/'). '/setup';
|
||||
$start_settings['real_url'] = request()->url();
|
||||
$start_settings['url_valid'] = $start_settings['url_config'] === $start_settings['real_url'];
|
||||
$start_settings['php_version_min'] = true;
|
||||
|
||||
// Curl the .env file to make sure it's not accessible via a browser
|
||||
$start_settings['env_exposed'] = $this->dotEnvFileIsExposed();
|
||||
|
||||
if (App::Environment('production') && (true == config('app.debug'))) {
|
||||
$start_settings['debug_exposed'] = true;
|
||||
} else {
|
||||
$start_settings['debug_exposed'] = false;
|
||||
}
|
||||
|
||||
$environment = app()->environment();
|
||||
if ('production' != $environment) {
|
||||
$start_settings['env'] = $environment;
|
||||
$start_settings['prod'] = false;
|
||||
} else {
|
||||
$start_settings['env'] = $environment;
|
||||
$start_settings['prod'] = true;
|
||||
}
|
||||
|
||||
$start_settings['owner'] = '';
|
||||
|
||||
if (function_exists('posix_getpwuid')) { // Probably Linux
|
||||
$owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME']));
|
||||
// This *should* be an array, but we've seen this return a bool in some chrooted environments
|
||||
if (is_array($owner)) {
|
||||
$start_settings['owner'] = $owner['name'];
|
||||
}
|
||||
}
|
||||
|
||||
if (($start_settings['owner'] === 'root') || ($start_settings['owner'] === '0')) {
|
||||
$start_settings['owner_is_admin'] = true;
|
||||
} else {
|
||||
$start_settings['owner_is_admin'] = false;
|
||||
}
|
||||
|
||||
$start_settings['writable'] = $this->storagePathIsWritable();
|
||||
|
||||
$start_settings['gd'] = extension_loaded('gd');
|
||||
|
||||
return view('setup/index')
|
||||
->with('step', 1)
|
||||
->with('start_settings', $start_settings)
|
||||
->with('section', trans('general.setup_config_check'))
|
||||
->with('icon', 'fa-regular fa-rectangle-list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the .env file accessible via a browser.
|
||||
*
|
||||
* @return bool This method will return true when exceptions (such as curl exception) is thrown.
|
||||
* Check the log files to see more details about the exception.
|
||||
*/
|
||||
protected function dotEnvFileIsExposed() : bool
|
||||
{
|
||||
try {
|
||||
return Http::withoutVerifying()->timeout(10)
|
||||
->accept('*/*')
|
||||
->get(URL::to('.env'))
|
||||
->successful();
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e->getMessage());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the app storage path is writable.
|
||||
*/
|
||||
protected function storagePathIsWritable(): bool
|
||||
{
|
||||
return File::isWritable(storage_path()) &&
|
||||
File::isWritable(storage_path('framework')) &&
|
||||
File::isWritable(storage_path('framework/cache')) &&
|
||||
File::isWritable(storage_path('framework/sessions')) &&
|
||||
File::isWritable(storage_path('framework/views')) &&
|
||||
File::isWritable(storage_path('logs'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the first admin user from Setup.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
*
|
||||
*/
|
||||
public function postSaveFirstAdmin(SetupUserRequest $request) : RedirectResponse
|
||||
{
|
||||
|
||||
$user = new User();
|
||||
$user->first_name = $data['first_name'] = $request->input('first_name');
|
||||
$user->last_name = $request->input('last_name');
|
||||
$user->email = $data['email'] = $request->input('email');
|
||||
$user->activated = 1;
|
||||
$permissions = ['superuser' => 1];
|
||||
$user->permissions = json_encode($permissions);
|
||||
$user->username = $data['username'] = $request->input('username');
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
$data['password'] = $request->input('password');
|
||||
|
||||
$settings = new Setting();
|
||||
$settings->full_multiple_companies_support = $request->input('full_multiple_companies_support', 0);
|
||||
$settings->site_name = $request->input('site_name');
|
||||
$settings->alert_email = $request->input('email');
|
||||
$settings->alerts_enabled = 1;
|
||||
$settings->pwd_secure_min = 10;
|
||||
$settings->brand = 1;
|
||||
$settings->link_light_color = $request->input('link_light_color', '#296282');
|
||||
$settings->link_dark_color = $request->input('link_dark_color', '#296282');
|
||||
$settings->nav_link_color = $request->input('nav_link_color', '#FFFFFF');
|
||||
$settings->locale = $request->input('locale', 'en-US');
|
||||
$settings->default_currency = $request->input('default_currency', 'USD');
|
||||
$settings->created_by = 1;
|
||||
$settings->email_domain = $request->input('email_domain');
|
||||
$settings->email_format = $request->input('email_format');
|
||||
$settings->next_auto_tag_base = 1;
|
||||
$settings->auto_increment_assets = $request->input('auto_increment_assets', 0);
|
||||
$settings->auto_increment_prefix = $request->input('auto_increment_prefix');
|
||||
$settings->zerofill_count = $request->input('zerofill_count') ?: 0;
|
||||
|
||||
if ((! $user->isValid()) || (! $settings->isValid())) {
|
||||
return redirect()->back()->withInput()->withErrors($user->getErrors())->withErrors($settings->getErrors());
|
||||
} else {
|
||||
$user->save();
|
||||
Auth::login($user, true);
|
||||
$settings->save();
|
||||
|
||||
if ($request->input('email_creds') == '1') {
|
||||
$data = [];
|
||||
$data['email'] = $user->email;
|
||||
$data['username'] = $user->username;
|
||||
$data['first_name'] = $user->first_name;
|
||||
$data['last_name'] = $user->last_name;
|
||||
$data['password'] = $request->input('password');
|
||||
$user->notify(new FirstAdminNotification($data));
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->route('setup.done')
|
||||
->with('section', trans('general.setup_create_admin'))
|
||||
->with('icon', 'fa-solid fa-champagne-glasses')
|
||||
->with('success', trans('admin/settings/general.create_admin_success'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the admin user creation form in Setup.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v3.0]
|
||||
*/
|
||||
public function getSetupUser() : View
|
||||
{
|
||||
return view('setup/user')
|
||||
->with('step', 3)
|
||||
->with('section', trans('general.setup_create_admin'))
|
||||
->with('icon', 'fa-solid fa-user-plus');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the view that tells the user that the Setup is done.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v3.0]
|
||||
*/
|
||||
public function getSetupDone() : View
|
||||
{
|
||||
return view('setup/done')
|
||||
->with('success', trans('general.create_admin_success'))
|
||||
->with('step', 4)
|
||||
->with('icon', 'fa-solid fa-champagne-glasses fa-shake')
|
||||
->with('section', trans('general.setup_done'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Migrate the database tables, and return the output
|
||||
* to a view for Setup.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*
|
||||
* @since [v3.0]
|
||||
*/
|
||||
public function setupMigrate()
|
||||
{
|
||||
Artisan::call('migrate', ['--force' => true]);
|
||||
$output = Artisan::output();
|
||||
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
|
||||
Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]);
|
||||
Artisan::call('passport:install', ['--no-interaction' => true]);
|
||||
}
|
||||
|
||||
return view('setup/migrate')
|
||||
->with('success', trans('general.create_admin_success'))
|
||||
->with('output', trim($output))
|
||||
->with('step', 2)
|
||||
->with('section', trans('general.setup_create_database'))
|
||||
->with('icon', 'fa-solid fa-database');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Import;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
@@ -155,7 +157,31 @@ class UploadedFilesController extends Controller
|
||||
}
|
||||
|
||||
// The file doesn't seem to really exist, so report an error
|
||||
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.error', 1));
|
||||
return redirect()->back()->withFragment('files')->with('error', trans_choice('general.file_upload_status.delete.error', 1));
|
||||
|
||||
}
|
||||
|
||||
public function downloadImport(Import $import) {
|
||||
|
||||
$this->authorize('import');
|
||||
|
||||
if ($import = Import::find($import->id)) {
|
||||
|
||||
if ((auth()->user()->id != $import->created_by) && (!auth()->user()->isSuperUser())) {
|
||||
return redirect()->back()->with('error', trans('general.file_upload_status.file_not_found'));
|
||||
}
|
||||
|
||||
if (config('filesystems.default') == 's3_private') {
|
||||
return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/imports/' . $import->file_path, now()->addMinutes(5)));
|
||||
}
|
||||
|
||||
if (Storage::exists('private_uploads/imports/' . $import->file_path)) {
|
||||
return response()->download(config('app.private_uploads') . '/imports/' . $import->file_path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('general.file_upload_status.file_not_found'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ class Kernel extends HttpKernel
|
||||
\App\Http\Middleware\CheckForTwoFactor::class,
|
||||
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
|
||||
\App\Http\Middleware\AssetCountForSidebar::class,
|
||||
\App\Http\Middleware\CheckColorSettings::class,
|
||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class CheckColorSettings
|
||||
{
|
||||
/**
|
||||
* The Guard implementation.
|
||||
*
|
||||
* @var Guard
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Create a new filter instance.
|
||||
*
|
||||
* @param Guard $auth
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Guard $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
|
||||
// Set defaults in case this is accessed via the /setup screen
|
||||
$nav_color = '#ffffff';
|
||||
$link_dark_color = '#89c9ed';
|
||||
$link_light_color = '#3c8dbc';
|
||||
|
||||
|
||||
if ($settings = Setting::getSettings()) {
|
||||
$nav_color = $settings->nav_link_color;
|
||||
$link_dark_color = $settings->link_dark_color;
|
||||
$link_light_color = $settings->link_light_color;
|
||||
}
|
||||
|
||||
|
||||
// Override system settings
|
||||
if ($request->user()) {
|
||||
|
||||
if ($request->user()->nav_color) {
|
||||
$nav_color = $request->user()->nav_color;
|
||||
}
|
||||
if ($request->user()->link_dark_color) {
|
||||
$link_dark_color = $request->user()->link_dark_color;
|
||||
}
|
||||
if ($request->user()->nav_color) {
|
||||
$link_light_color = $request->user()->link_light_color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
view()->share('nav_link_color', $nav_color);
|
||||
view()->share('link_dark_color', $link_dark_color);
|
||||
view()->share('link_light_color', $link_light_color);
|
||||
|
||||
return $next($request);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Traits\MayContainCustomFields;
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Setting;
|
||||
use App\Models\AssetModel;
|
||||
use App\Rules\UniqueUndeleted;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CreateMultipleAssetRequest extends ImageUploadRequest //should I extend from StoreAssetRequest? FIXME OR TODO OR THINKME
|
||||
{
|
||||
use MayContainCustomFields;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true; //TODO - should I do the auth check here?
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
//grab the rules for serials and asset_tags, and tweak them into an array context for multi-create usage
|
||||
$modelRules = (new Asset)->getRules();
|
||||
unset($modelRules['serial']);
|
||||
|
||||
$asset_tag_rules = $modelRules['asset_tag'];
|
||||
unset($modelRules['asset_tag']);
|
||||
// now we replace the 'not_array' rule with 'distinct'
|
||||
array_splice($asset_tag_rules, array_search('not_array', $asset_tag_rules), 1, 'distinct');
|
||||
// and replace the 'unique_undeleted' rule with the Rule object
|
||||
foreach ($asset_tag_rules as $i => $asset_tag_rule) {
|
||||
if (Str::startsWith($asset_tag_rule, 'unique_undeleted')) {
|
||||
$asset_tag_rules[$i] = new UniqueUndeleted('assets', 'asset_tag');
|
||||
}
|
||||
}
|
||||
|
||||
$serials_unique = Setting::getSettings()['unique_serial'];
|
||||
$serials_required = AssetModel::find($this?->model_id)?->require_serial;
|
||||
|
||||
$serial_rules = ['string'];
|
||||
if ($serials_unique) {
|
||||
// $serial_rules[] = 'unique_undeleted:assets,serial';
|
||||
$serial_rules[] = new UniqueUndeleted('assets', 'serial');
|
||||
$serial_rules[] = 'distinct';
|
||||
}
|
||||
if ($serials_required) {
|
||||
$serial_rules[] = 'required';
|
||||
} else {
|
||||
$serial_rules[] = 'nullable';
|
||||
}
|
||||
|
||||
return array_merge($modelRules, [
|
||||
'serials.*' => $serial_rules,
|
||||
'asset_tags.*' => $asset_tag_rules,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ class SetupUserRequest extends Request
|
||||
'username' => 'required|string|min:2|unique:users,username,NULL,deleted_at',
|
||||
'email' => 'email|unique:users,email',
|
||||
'password' => 'required|min:8|confirmed',
|
||||
'email_domain' => 'required|min:4',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ abstract class Importer
|
||||
'min_amt' => 'minimum quantity',
|
||||
'remote' => 'remote',
|
||||
'vip' => 'vip',
|
||||
'tag_color' => 'tag color',
|
||||
];
|
||||
/**
|
||||
* Map of item fields->csv names
|
||||
|
||||
@@ -75,6 +75,7 @@ class LocationImporter extends ItemImporter
|
||||
$this->item['manager'] = trim($this->findCsvMatch($row, 'manager'));
|
||||
$this->item['manager_username'] = trim($this->findCsvMatch($row, 'manager_username'));
|
||||
$this->item['notes'] = trim($this->findCsvMatch($row, 'notes'));
|
||||
$this->item['tag_color'] = trim($this->findCsvMatch($row, 'tag_color'));
|
||||
|
||||
|
||||
if ($this->findCsvMatch($row, 'parent_location')) {
|
||||
@@ -96,6 +97,9 @@ class LocationImporter extends ItemImporter
|
||||
$location->update($this->sanitizeItemForUpdating($location));
|
||||
} else {
|
||||
Log::debug('Creating location');
|
||||
if ($this->findCsvMatch($row, 'company')) {
|
||||
$this->item['company_id'] = $this->createOrFetchCompany(trim($this->findCsvMatch($row, 'company')));
|
||||
}
|
||||
$location->fill($this->sanitizeItemForStoring($location));
|
||||
}
|
||||
|
||||
|
||||
@@ -347,6 +347,7 @@ class Importer extends Component
|
||||
|
||||
$this->locations_fields = [
|
||||
'id' => trans('general.id'),
|
||||
'company' => trans('general.company'),
|
||||
'name' => trans('general.name'),
|
||||
'address' => trans('general.address'),
|
||||
'address2' => trans('general.importer.address2'),
|
||||
@@ -360,6 +361,7 @@ class Importer extends Component
|
||||
'parent_location' => trans('admin/locations/table.parent'),
|
||||
'state' => trans('general.state'),
|
||||
'zip' => trans('general.zip'),
|
||||
'tag_color' => trans('general.tag_color'),
|
||||
];
|
||||
|
||||
$this->suppliers_fields = [
|
||||
@@ -608,6 +610,14 @@ class Importer extends Component
|
||||
[
|
||||
'Manager Username',
|
||||
],
|
||||
'tag_color' =>
|
||||
[
|
||||
'color',
|
||||
'tag color',
|
||||
'label color',
|
||||
'color code',
|
||||
trans('general.tag_color'),
|
||||
],
|
||||
];
|
||||
|
||||
$this->columnOptions[''] = $this->getColumns(''); //blank mode? I don't know what this is supposed to mean
|
||||
@@ -663,6 +673,13 @@ class Importer extends Component
|
||||
return;
|
||||
}
|
||||
|
||||
if ((auth()->user()->id != $import->created_by) && (!auth()->user()->isSuperUser())) {
|
||||
$this->message = trans('general.generic_model_not_found', ['model' => trans('general.import')]);
|
||||
$this->message_type = 'danger';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storage::delete('private_uploads/imports/' . $import->file_path)) {
|
||||
$import->delete();
|
||||
$this->message = trans('admin/hardware/message.import.file_delete_success');
|
||||
@@ -673,7 +690,7 @@ class Importer extends Component
|
||||
return;
|
||||
}
|
||||
|
||||
$this->message = trans('admin/hardware/message.import.file_delete_error');
|
||||
$this->message = trans('general.generic_model_not_found', ['model' => trans('general.import')]);
|
||||
$this->message_type = 'danger';
|
||||
}
|
||||
|
||||
|
||||
@@ -246,6 +246,19 @@ class Accessory extends SnipeModel
|
||||
->with('assignedTo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the accessory -> users relationship
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
return $this->belongsToMany(\App\Models\AccessoryCheckout::class, 'accessories_checkout')
|
||||
->with('assignedTo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the accessory -> admin user relationship
|
||||
*
|
||||
|
||||
@@ -48,6 +48,30 @@ class CheckoutAcceptance extends Model
|
||||
default => class_basename($type),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Accessor for the checkoutable item's category name.
|
||||
*
|
||||
* @return Attribute
|
||||
*/
|
||||
protected function checkoutableCategoryName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function () {
|
||||
$item = $this->checkoutable;
|
||||
|
||||
if ($item instanceof Asset) {
|
||||
|
||||
return $item->model?->category?->name;
|
||||
}
|
||||
if ($item instanceof LicenseSeat) {
|
||||
|
||||
return $item->license?->category?->name;
|
||||
}
|
||||
|
||||
return $item->category?->name;
|
||||
},
|
||||
);
|
||||
}
|
||||
/**
|
||||
* The resource that was is out
|
||||
*
|
||||
|
||||
@@ -13,7 +13,7 @@ class Checkoutable
|
||||
public string $name,
|
||||
public string $type,
|
||||
public object $acceptance,
|
||||
public object $assignee,
|
||||
public readonly User|Asset|Location|null $assignee,
|
||||
public readonly string $plain_text_category,
|
||||
public readonly string $plain_text_model,
|
||||
public readonly string $plain_text_name,
|
||||
@@ -43,8 +43,8 @@ class Checkoutable
|
||||
$name = optional($unaccepted_row->present())->nameUrl() ?? '';
|
||||
}
|
||||
if($unaccepted_row instanceof LicenseSeat){
|
||||
$category = optional($unaccepted_row->license->category?->present())->nameUrl() ?? '';
|
||||
$company = optional($unaccepted_row->license->company?->present())?->nameUrl() ?? '';
|
||||
$category = optional($unaccepted_row->license?->category?->present())->nameUrl() ?? '';
|
||||
$company = optional($unaccepted_row->license?->company?->present())?->nameUrl() ?? '';
|
||||
$model = '';
|
||||
$name = $unaccepted_row->license->present()->nameUrl() ?? '';
|
||||
}
|
||||
|
||||
@@ -110,6 +110,18 @@ class Component extends SnipeModel
|
||||
'manufacturer' => ['name'],
|
||||
];
|
||||
|
||||
public static function booted()
|
||||
{
|
||||
static::saving(function ($model) {
|
||||
// We use 'sum_unconstrained_assets' as a 'cache' of the count of the sum of unconstrained assets, but
|
||||
// Eloquent will gladly try to save the value of that attribute in the case where we populate it ourselves.
|
||||
// But when it gets populated by 'withSum()' - it seems to work fine due to some Eloquent magic I am not
|
||||
// aware of. During a save, the quantity may have changed or other aspects may have changed, so
|
||||
// "invalidating the 'cache'" seems like a fair choice here.
|
||||
unset($model->sum_unconstrained_assets);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public function isDeletable()
|
||||
{
|
||||
@@ -238,14 +250,28 @@ class Component extends SnipeModel
|
||||
* @since [v5.0]
|
||||
* @return int
|
||||
*/
|
||||
public function numCheckedOut()
|
||||
public function numCheckedOut(bool $recalculate = false)
|
||||
{
|
||||
$checkedout = 0;
|
||||
/**
|
||||
*
|
||||
* WARNING: This method caches the result, so if you're doing something
|
||||
* that is going to change the number of checked-out items, make sure to pass
|
||||
* 'true' as the first parameter to force this to recalculate the number of checked-out
|
||||
* items!!!!!
|
||||
*
|
||||
*/
|
||||
|
||||
// In case there are elements checked out to assets that belong to a different company
|
||||
// than this asset and full multiple company support is on we'll remove the global scope,
|
||||
// so they are included in the count.
|
||||
return $this->uncontrainedAssets->sum('pivot.assigned_qty');
|
||||
if (is_null($this->sum_unconstrained_assets) || $recalculate) {
|
||||
// This, in a components-listing context, is mostly important for when it sets a 'zero' which
|
||||
// is *not* null - so we don't have to keep recalculating for un-checked-out components
|
||||
// NOTE: doing this will add a 'pseudo-attribute' to the component in question, so we need to _remove_ this
|
||||
// before we save - so that gets handled in the 'saving' callback defined in the 'booted' method, above.
|
||||
$this->sum_unconstrained_assets = $this->uncontrainedAssets()->sum('assigned_qty') ?? 0;
|
||||
}
|
||||
return $this->sum_unconstrained_assets;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -95,23 +95,39 @@ class L4736_A extends L4736
|
||||
$currentX += $barcodeSize + self::BARCODE_MARGIN;
|
||||
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
|
||||
}
|
||||
$fields = $record->get('fields');
|
||||
$fieldCount = count($fields);
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
$perFieldHeight = (self::LABEL_SIZE + self::LABEL_MARGIN)
|
||||
+ (self::FIELD_SIZE + self::FIELD_MARGIN);
|
||||
|
||||
$baseHeight = $fieldCount * $perFieldHeight;
|
||||
$scale = 1.0;
|
||||
if ($baseHeight > $usableHeight && $baseHeight > 0) {
|
||||
$scale = $usableHeight / $baseHeight;
|
||||
}
|
||||
|
||||
$labelSize = self::LABEL_SIZE * $scale;
|
||||
$labelMargin = self::LABEL_MARGIN * $scale;
|
||||
$fieldSize = self::FIELD_SIZE * $scale;
|
||||
$fieldMargin = self::FIELD_MARGIN * $scale;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
static::writeText(
|
||||
$pdf, $field['label'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::LABEL_SIZE, 'L',
|
||||
$usableWidth, self::LABEL_SIZE, true, 0
|
||||
'freesans', '', $labelSize, 'L',
|
||||
$usableWidth, $labelSize, true, 0
|
||||
);
|
||||
$currentY += self::LABEL_SIZE + self::LABEL_MARGIN;
|
||||
$currentY += $labelSize + $labelMargin;
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freemono', 'B', self::FIELD_SIZE, 'L',
|
||||
$usableWidth, self::FIELD_SIZE, true, 0, 0.01
|
||||
'freemono', 'B', $fieldSize, 'L',
|
||||
$usableWidth, $fieldSize, true, 0, 0.01
|
||||
);
|
||||
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
|
||||
$currentY += $fieldSize + $fieldMargin;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,23 +59,44 @@ class L6009_A extends L6009
|
||||
$currentX += $barcodeSize + self::BARCODE_MARGIN;
|
||||
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
|
||||
}
|
||||
$fields = $record->get('fields');
|
||||
// Below rescales the size of the field box to fit, it feels like it could/should be abstracted one class above
|
||||
// to be usable on other labels but im unsure of how to implement that, since it uses a lot of private
|
||||
// constants.
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
// Figure out how tall the label fields wants to be
|
||||
$fieldCount = count($fields);
|
||||
$perFieldHeight = (self::LABEL_SIZE + self::LABEL_MARGIN)
|
||||
+ (self::FIELD_SIZE + self::FIELD_MARGIN);
|
||||
|
||||
$baseHeight = $fieldCount * $perFieldHeight;
|
||||
// If it doesn't fit in the available height, scale everything down
|
||||
$scale = 1.0;
|
||||
if ($baseHeight > $usableHeight && $baseHeight > 0) {
|
||||
$scale = $usableHeight / $baseHeight;
|
||||
}
|
||||
|
||||
$labelSize = self::LABEL_SIZE * $scale;
|
||||
$labelMargin = self::LABEL_MARGIN * $scale;
|
||||
$fieldSize = self::FIELD_SIZE * $scale;
|
||||
$fieldMargin = self::FIELD_MARGIN * $scale;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
static::writeText(
|
||||
$pdf, $field['label'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::LABEL_SIZE, 'L',
|
||||
$usableWidth, self::LABEL_SIZE, true, 0
|
||||
'freesans', '', $labelSize, 'L',
|
||||
$usableWidth, $labelSize, true, 0
|
||||
);
|
||||
$currentY += self::LABEL_SIZE + self::LABEL_MARGIN;
|
||||
$currentY += $labelSize + $labelMargin;
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freemono', 'B', self::FIELD_SIZE, 'L',
|
||||
$usableWidth, self::FIELD_SIZE, true, 0, 0.01
|
||||
'freemono', 'B', $fieldSize, 'L',
|
||||
$usableWidth, $fieldSize, true, 0, 0.01
|
||||
);
|
||||
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
|
||||
$currentY += $fieldSize + $fieldMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Labels\Tapes\Brother;
|
||||
|
||||
class TZe_241 extends TZe_18mm
|
||||
{
|
||||
private const LABEL_SIZE = 5.0;
|
||||
private const LABEL_MARGIN = 0.6;
|
||||
private const FIELD_SIZE = 5.0;
|
||||
private const FIELD_MARGIN = 0.8;
|
||||
|
||||
public function getUnit()
|
||||
{
|
||||
return 'mm';
|
||||
}
|
||||
public function getWidth()
|
||||
{
|
||||
return 50.0;
|
||||
}
|
||||
public function getSupportAssetTag()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public function getSupport1DBarcode()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public function getSupport2DBarcode()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public function getSupportFields()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
public function getSupportLogo()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public function getSupportTitle()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function preparePDF($pdf){}
|
||||
|
||||
public function write($pdf, $record)
|
||||
{
|
||||
$pa = $this->getPrintableArea();
|
||||
|
||||
$currentX = $pa->x1;
|
||||
$currentY = $pa->y1;
|
||||
$usableWidth = $pa->w;
|
||||
$usableHeight = $pa->h;
|
||||
|
||||
$fields = $record->get('fields') ?? [];
|
||||
|
||||
$fieldCount = count($fields);
|
||||
|
||||
$perFieldHeight = (self::LABEL_SIZE + self::LABEL_MARGIN)
|
||||
+ (self::FIELD_SIZE + self::FIELD_MARGIN);
|
||||
|
||||
$baseHeight = $fieldCount * $perFieldHeight;
|
||||
|
||||
// If it doesn't fit in the available height, scale everything down
|
||||
$scale = 1.0;
|
||||
if ($baseHeight > $usableHeight && $baseHeight > 0) {
|
||||
$scale = $usableHeight / $baseHeight;
|
||||
}
|
||||
|
||||
$labelSize = self::LABEL_SIZE * $scale;
|
||||
$labelMargin = self::LABEL_MARGIN * $scale;
|
||||
$fieldSize = self::FIELD_SIZE * $scale;
|
||||
$fieldMargin = self::FIELD_MARGIN * $scale;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
static::writeText(
|
||||
$pdf, $field['label'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', $labelSize, 'L',
|
||||
$usableWidth, $labelSize, true, 0
|
||||
);
|
||||
$currentY += $labelSize + $labelMargin;
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freemono', 'B', $fieldSize, 'L',
|
||||
$usableWidth, $fieldSize, true, 0, 0.01
|
||||
);
|
||||
$currentY += $fieldSize + $fieldMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,12 +30,12 @@ class TZe_24mm_E extends TZe_24mm
|
||||
$pa = $this->getPrintableArea();
|
||||
|
||||
$currentX = $pa->x1;
|
||||
$currentY = $pa->y1;
|
||||
$currentY = $pa->y1 -2;
|
||||
$usableWidth = $pa->w;
|
||||
|
||||
|
||||
$usableHeight = $pa->h - self::BARCODE1D_SIZE;
|
||||
$barcodeSize = $usableHeight - self::TAG_SIZE;
|
||||
$barcodeSize = ($usableHeight - self::TAG_SIZE) * 1.2;
|
||||
|
||||
if ($record->has('barcode2d')) {
|
||||
static::writeText(
|
||||
@@ -70,10 +70,27 @@ class TZe_24mm_E extends TZe_24mm
|
||||
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
|
||||
}
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
$fields = $record->get('fields');
|
||||
// Figure out how tall the label fields wants to be
|
||||
$fieldCount = count($fields);
|
||||
$perFieldHeight = (self::LABEL_SIZE + self::LABEL_MARGIN)
|
||||
+ (self::FIELD_SIZE + self::FIELD_MARGIN);
|
||||
|
||||
$baseHeight = $fieldCount * $perFieldHeight;
|
||||
// If it doesn't fit in the available height, scale everything down
|
||||
$scale = 1.0;
|
||||
if ($baseHeight > $usableHeight && $baseHeight > 0) {
|
||||
$scale = $usableHeight / $baseHeight;
|
||||
}
|
||||
|
||||
$labelSize = self::LABEL_SIZE * $scale;
|
||||
$fieldSize = self::FIELD_SIZE * $scale;
|
||||
$fieldMargin = self::FIELD_MARGIN * $scale;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
// Write label and value on the same line
|
||||
// Calculate label width with proportional character spacing
|
||||
$labelWidth = $pdf->GetStringWidth($field['label'], 'freesans', '', self::LABEL_SIZE);
|
||||
$labelWidth = $pdf->GetStringWidth($field['label'], 'freesans', '', $labelSize);
|
||||
$charCount = strlen($field['label']);
|
||||
$spacingPerChar = 0.5;
|
||||
$totalSpacing = $charCount * $spacingPerChar;
|
||||
@@ -82,18 +99,18 @@ class TZe_24mm_E extends TZe_24mm
|
||||
static::writeText(
|
||||
$pdf, $field['label'],
|
||||
$currentX, $currentY,
|
||||
'freesans', 'B', self::LABEL_SIZE, 'L',
|
||||
$adjustedWidth, self::LABEL_SIZE, true, 0, $spacingPerChar
|
||||
'freesans', 'B', $labelSize, 'L',
|
||||
$adjustedWidth, $labelSize, true, 0, $spacingPerChar
|
||||
);
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['value'],
|
||||
$currentX + $adjustedWidth + 2, $currentY,
|
||||
'freesans', 'B', self::FIELD_SIZE, 'L',
|
||||
$usableWidth - $adjustedWidth - 2, self::FIELD_SIZE, true, 0, 0.3
|
||||
'freesans', 'B', $fieldSize, 'L',
|
||||
$usableWidth - $adjustedWidth - 2, $fieldSize, true, 0, 0.3
|
||||
);
|
||||
|
||||
$currentY += max(self::LABEL_SIZE, self::FIELD_SIZE) + self::FIELD_MARGIN;
|
||||
$currentY += max($labelSize, $fieldSize) +$fieldMargin;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ class LabelWriter_11354 extends LabelWriter
|
||||
private const TITLE_MARGIN = 0.50;
|
||||
private const FIELD_SIZE = 2.80;
|
||||
private const FIELD_MARGIN = 0.15;
|
||||
private const LABEL_SIZE = 2.8;
|
||||
private const LABEL_MARGIN = 0.6;
|
||||
|
||||
public function getUnit()
|
||||
{
|
||||
@@ -102,14 +104,47 @@ class LabelWriter_11354 extends LabelWriter
|
||||
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
|
||||
}
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
$fields = $record->get('fields');
|
||||
// Below rescales the size of the field box to fit, it feels like it could/should be abstracted one class above
|
||||
// to be usable on other labels but im unsure of how to implement that, since it uses a lot of private
|
||||
// constants.
|
||||
|
||||
// Figure out how tall the label fields wants to be
|
||||
$fieldCount = count($fields);
|
||||
$perFieldHeight = (self::LABEL_SIZE + self::LABEL_MARGIN)
|
||||
+ (self::FIELD_SIZE + self::FIELD_MARGIN);
|
||||
$usableHeight = $pa->h
|
||||
- self::TAG_SIZE
|
||||
- self::BARCODE_MARGIN;
|
||||
|
||||
$baseHeight = $fieldCount * $perFieldHeight;
|
||||
// If it doesn't fit in the available height, scale everything down
|
||||
$scale = 1.0;
|
||||
if ($baseHeight > $usableHeight && $baseHeight > 0) {
|
||||
$scale = $usableHeight / $baseHeight;
|
||||
}
|
||||
|
||||
$labelSize = self::LABEL_SIZE * $scale;
|
||||
$labelMargin = self::LABEL_MARGIN * $scale;
|
||||
$fieldSize = self::FIELD_SIZE * $scale;
|
||||
$fieldMargin = self::FIELD_MARGIN * $scale;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
static::writeText(
|
||||
$pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'],
|
||||
$pdf, $field['label'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::FIELD_SIZE, 'L',
|
||||
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
|
||||
'freesans', '', $labelSize, 'L',
|
||||
$usableWidth, $labelSize, true, 0
|
||||
);
|
||||
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
|
||||
$currentY += $labelSize + $labelMargin;
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freemono', 'B', $fieldSize, 'L',
|
||||
$usableWidth, $fieldSize, true, 0, 0.01
|
||||
);
|
||||
$currentY += $fieldSize + $fieldMargin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,14 +91,47 @@ class LabelWriter_1933081 extends LabelWriter
|
||||
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
|
||||
}
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
$fields = $record->get('fields');
|
||||
// Below rescales the size of the field box to fit, it feels like it could/should be abstracted one class above
|
||||
// to be usable on other labels but im unsure of how to implement that, since it uses a lot of private
|
||||
// constants.
|
||||
|
||||
// Figure out how tall the label fields wants to be
|
||||
$fieldCount = count($fields);
|
||||
$perFieldHeight = (self::LABEL_SIZE + self::LABEL_MARGIN)
|
||||
+ (self::FIELD_SIZE + self::FIELD_MARGIN);
|
||||
$usableHeight = $pa->h
|
||||
- self::TAG_SIZE // bottom tag text
|
||||
- self::BARCODE_MARGIN; // gap between fields and 1D
|
||||
|
||||
$baseHeight = $fieldCount * $perFieldHeight;
|
||||
// If it doesn't fit in the available height, scale everything down
|
||||
$scale = 1.0;
|
||||
if ($baseHeight > $usableHeight && $baseHeight > 0) {
|
||||
$scale = $usableHeight / $baseHeight;
|
||||
}
|
||||
|
||||
$labelSize = self::LABEL_SIZE * $scale;
|
||||
$labelMargin = self::LABEL_MARGIN * $scale;
|
||||
$fieldSize = self::FIELD_SIZE * $scale;
|
||||
$fieldMargin = self::FIELD_MARGIN * $scale;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
static::writeText(
|
||||
$pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'],
|
||||
$pdf, $field['label'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::FIELD_SIZE, 'L',
|
||||
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
|
||||
'freesans', '', $labelSize, 'L',
|
||||
$usableWidth, $labelSize, true, 0
|
||||
);
|
||||
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
|
||||
$currentY += $labelSize + $labelMargin;
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freemono', 'B', $fieldSize, 'L',
|
||||
$usableWidth, $fieldSize, true, 0, 0.01
|
||||
);
|
||||
$currentY += $fieldSize + $fieldMargin;
|
||||
}
|
||||
|
||||
if ($record->has('barcode1d')) {
|
||||
|
||||
@@ -91,16 +91,48 @@ class LabelWriter_2112283 extends LabelWriter
|
||||
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
|
||||
}
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
static::writeText(
|
||||
$pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::FIELD_SIZE, 'L',
|
||||
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
|
||||
);
|
||||
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
|
||||
$fields = $record->get('fields');
|
||||
// Below rescales the size of the field box to fit, it feels like it could/should be abstracted one class above
|
||||
// to be usable on other labels but im unsure of how to implement that, since it uses a lot of private
|
||||
// constants.
|
||||
|
||||
// Figure out how tall the label fields wants to be
|
||||
$fieldCount = count($fields);
|
||||
$perFieldHeight = (self::LABEL_SIZE + self::LABEL_MARGIN)
|
||||
+ (self::FIELD_SIZE + self::FIELD_MARGIN);
|
||||
$usableHeight = $pa->h
|
||||
- self::TAG_SIZE // bottom tag text
|
||||
- self::BARCODE_MARGIN; // gap between fields and 1D
|
||||
|
||||
$baseHeight = $fieldCount * $perFieldHeight;
|
||||
// If it doesn't fit in the available height, scale everything down
|
||||
$scale = 1.0;
|
||||
if ($baseHeight > $usableHeight && $baseHeight > 0) {
|
||||
$scale = $usableHeight / $baseHeight;
|
||||
}
|
||||
|
||||
$labelSize = self::LABEL_SIZE * $scale;
|
||||
$labelMargin = self::LABEL_MARGIN * $scale;
|
||||
$fieldSize = self::FIELD_SIZE * $scale;
|
||||
$fieldMargin = self::FIELD_MARGIN * $scale;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
static::writeText(
|
||||
$pdf, $field['label'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', $labelSize, 'L',
|
||||
$usableWidth, $labelSize, true, 0
|
||||
);
|
||||
$currentY += $labelSize + $labelMargin;
|
||||
|
||||
static::writeText(
|
||||
$pdf, $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freemono', 'B', $fieldSize, 'L',
|
||||
$usableWidth, $fieldSize, true, 0, 0.01
|
||||
);
|
||||
$currentY += $fieldSize + $fieldMargin;
|
||||
}
|
||||
if ($record->has('barcode1d')) {
|
||||
static::write1DBarcode(
|
||||
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
|
||||
|
||||
@@ -784,21 +784,24 @@ class License extends Depreciable
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
* @see \App\Console\Commands\SendExpiringLicenseNotifications
|
||||
*/
|
||||
public function scopeExpiringLicenses($query, $days = 60)
|
||||
public function scopeExpiringLicenses($query, $days = 60, $includeExpired = false)
|
||||
{
|
||||
return $query// The termination date is null or within range
|
||||
->where(function ($query) use ($days) {
|
||||
$query->whereNull('termination_date')
|
||||
->orWhereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]);
|
||||
})
|
||||
->where(function ($query) use ($days) {
|
||||
->where(function ($query) use ($days, $includeExpired) {
|
||||
$query->whereNotNull('expiration_date')
|
||||
// Handle expiring licenses without termination dates
|
||||
->where(function ($query) use ($days) {
|
||||
->where(function ($query) use ($days, $includeExpired) {
|
||||
$query->whereNull('termination_date')
|
||||
->whereBetween('expiration_date', [Carbon::now(), Carbon::now()->addDays($days)]);
|
||||
->whereBetween('expiration_date', [Carbon::now(), Carbon::now()->addDays($days)])
|
||||
//include expired licenses if requested
|
||||
->when($includeExpired, function ($query) use ($days) {
|
||||
$query->orwhereDate('expiration_date', '<=', Carbon::now());
|
||||
});
|
||||
})
|
||||
|
||||
// Handle expiring licenses with termination dates in the future
|
||||
->orWhere(function ($query) use ($days) {
|
||||
$query->whereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]);
|
||||
|
||||
@@ -35,7 +35,7 @@ class Supplier extends SnipeModel
|
||||
'state' => 'min:2|max:191|nullable',
|
||||
'country' => 'min:2|max:191|nullable',
|
||||
'zip' => 'max:10|nullable',
|
||||
'url' => 'sometimes|nullable|string|max:250',
|
||||
'url' => 'sometimes|url|nullable|string|max:250',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,7 +74,8 @@ class AcceptanceItemDeclinedNotification extends Notification
|
||||
'company_name' => $this->company_name,
|
||||
'qty' => $this->qty,
|
||||
'admin' => $this->admin,
|
||||
'intro_text' => trans('mail.acceptance_declined_greeting'),
|
||||
'user' => $this->assigned_to,
|
||||
'intro_text' => trans('mail.acceptance_declined_greeting', ['user' => $this->assigned_to]),
|
||||
])
|
||||
->subject('⚠️ '.trans('mail.acceptance_declined', ['user' => $this->assigned_to, 'item' => $this->item_name]))
|
||||
->withSymfonyMessage(function (Email $message) {
|
||||
|
||||
@@ -50,7 +50,12 @@ class ExpectedCheckinNotification extends Notification
|
||||
*/
|
||||
public function toMail()
|
||||
{
|
||||
$today = Carbon::now();
|
||||
$today = Carbon::today();
|
||||
$expected = Carbon::parse($this->params->expected_checkin)->startOfDay();
|
||||
|
||||
$subjectText = $today->greaterThan($expected)
|
||||
? trans('mail.Expected_Checkin_Notification_Pastdue', ['name' => $this->params->display_name])
|
||||
: trans('mail.Expected_Checkin_Notification', ['name' => $this->params->display_name]);
|
||||
|
||||
$message = (new MailMessage)->markdown('notifications.markdown.expected-checkin',
|
||||
[
|
||||
@@ -60,7 +65,7 @@ class ExpectedCheckinNotification extends Notification
|
||||
'serial' => $this->params->serial,
|
||||
'asset_tag' => $this->params->asset_tag,
|
||||
])
|
||||
->subject('⏰'. ($today > $this->params->expected_checkin) ? trans('mail.Expected_Checkin_Notification_Pastdue', ['name' => $this->params->display_name]) : trans('mail.Expected_Checkin_Notification', ['name' => $this->params->display_name]))
|
||||
->subject('⏰'. $subjectText)
|
||||
->withSymfonyMessage(function (Email $message) {
|
||||
$message->getHeaders()->addTextHeader(
|
||||
'X-System-Sender', 'Snipe-IT'
|
||||
|
||||
@@ -25,7 +25,7 @@ class InventoryAlert extends Notification
|
||||
public function __construct($params, $threshold)
|
||||
{
|
||||
$this->items = $params;
|
||||
$this->threshold = $threshold;
|
||||
$this->threshold = $threshold ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Contracts\Validation\ValidatorAwareRule;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Contracts\Validation\DataAwareRule;
|
||||
|
||||
class UniqueUndeleted implements ValidationRule, ValidatorAwareRule
|
||||
{
|
||||
protected ?Validator $validator = null;
|
||||
protected array $columns = [];
|
||||
protected $data = [];
|
||||
|
||||
public function __construct(
|
||||
public string $table,
|
||||
string ...$columns,
|
||||
)
|
||||
{
|
||||
$this->columns = $columns;
|
||||
}
|
||||
|
||||
public function setValidator(Validator $validator): static
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->data = $validator->getData();
|
||||
//TODO - can we somehow grab the ID of the route-model-bound object, and omit its ID?
|
||||
// to do that, we'd have to know _which_ parameter in the validator is actually the R-M-B'ed
|
||||
// parameter. Or maybe we just change the function signature to let you specify it.
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
$query = DB::table($this->table)->whereNull('deleted_at');
|
||||
$query->where($this->columns[0], '=', $value); //the first column to check
|
||||
$translation_string = 'validation.unique_undeleted'; //the normal validation string for a single-column check
|
||||
foreach (array_slice($this->columns, 1) as $column) {
|
||||
$translation_string = 'validation.two_column_unique_undeleted';
|
||||
$query->where($column, '=', $this->data[$column]);
|
||||
}
|
||||
|
||||
if ($query->count() > 0) {
|
||||
$fail($translation_string)->translate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,8 @@ $config = [
|
||||
'region' => env('PUBLIC_AWS_DEFAULT_REGION'),
|
||||
'bucket' => env('PUBLIC_AWS_BUCKET'),
|
||||
'url' => env('PUBLIC_AWS_URL'),
|
||||
'endpoint' => env('PUBLIC_AWS_ENDPOINT'),
|
||||
'use_path_style_endpoint' => env('PUBLIC_AWS_PATH_STYLE'),
|
||||
'root' => env('PUBLIC_AWS_BUCKET_ROOT'),
|
||||
'visibility' => 'public'
|
||||
],
|
||||
@@ -78,6 +80,8 @@ $config = [
|
||||
'region' => env('PRIVATE_AWS_DEFAULT_REGION'),
|
||||
'bucket' => env('PRIVATE_AWS_BUCKET'),
|
||||
'url' => env('PRIVATE_AWS_URL'),
|
||||
'endpoint' => env('PRIVATE_AWS_ENDPOINT'),
|
||||
'use_path_style_endpoint' => env('PRIVATE_AWS_PATH_STYLE'),
|
||||
'root' => env('PRIVATE_AWS_BUCKET_ROOT'),
|
||||
'visibility' => 'private'
|
||||
],
|
||||
@@ -168,4 +172,4 @@ $config['allowed_upload_mimetypes'] = implode(',', $config['allowed_upload_mimet
|
||||
$config['allowed_upload_extensions_for_validator'] = implode(',', $config['allowed_upload_extensions_array']);
|
||||
$config['allowed_upload_extensions'] = '.'.implode(', .', $config['allowed_upload_extensions_array']);
|
||||
|
||||
return $config;
|
||||
return $config;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
return array (
|
||||
'app_version' => 'v8.3.6',
|
||||
'full_app_version' => 'v8.3.6 - build 20551-g523df21d8',
|
||||
'build_version' => '20551',
|
||||
'app_version' => 'v8.3.7',
|
||||
'full_app_version' => 'v8.3.7 - build 20803-gdba8cb83b',
|
||||
'build_version' => '20803',
|
||||
'prerelease_version' => '',
|
||||
'hash_version' => 'g523df21d8',
|
||||
'full_hash' => 'v8.3.6-144-g523df21d8',
|
||||
'hash_version' => 'gdba8cb83b',
|
||||
'full_hash' => 'v8.3.7-250-gdba8cb83b',
|
||||
'branch' => 'master',
|
||||
);
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$setting = DB::table('settings')->select(['skin', 'header_color'])->first();
|
||||
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->string('link_dark_color')->after('header_color')->nullable()->default(null);
|
||||
$table->string('link_light_color')->after('header_color')->nullable()->default(null);
|
||||
$table->string('nav_link_color')->after('header_color')->nullable()->default('#ffffff');
|
||||
});
|
||||
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('link_dark_color')->after('skin')->nullable()->default(null);
|
||||
$table->string('link_light_color')->after('skin')->nullable()->default(null);
|
||||
$table->string('nav_link_color')->after('skin')->nullable()->default('#ffffff');
|
||||
});
|
||||
|
||||
|
||||
// Set Snipe-IT defaults
|
||||
$link_dark_color = '#89c9ed';
|
||||
$link_light_color = '#296282';
|
||||
$nav_color = '#ffffff';
|
||||
$header_color = '#3c8dbc';
|
||||
|
||||
if ($setting) {
|
||||
|
||||
switch ($setting->skin) {
|
||||
case ('green' || 'green-dark'):
|
||||
$header_color = '#00a65a';
|
||||
$link_dark_color = '#9ACD32';
|
||||
$link_light_color = '#00a65a';
|
||||
$nav_color = '#ffffff';
|
||||
break;
|
||||
|
||||
case ('red' || 'red-dark'):
|
||||
$header_color = '#dd4b39';
|
||||
$link_dark_color = '#ed9a9a';
|
||||
$link_light_color = '#dd4b39';
|
||||
$nav_color = '#ffffff';
|
||||
break;
|
||||
|
||||
case ('orange' || 'orange-dark'):
|
||||
$header_color = '#FF851B';
|
||||
$link_dark_color = '#FFA500';
|
||||
$link_light_color = '#FF8C00';
|
||||
$nav_color = '#ffffff';
|
||||
break;
|
||||
|
||||
case ('black' || 'black-dark'):
|
||||
$header_color = '#000000';
|
||||
$link_dark_color = '#d4d2d2';
|
||||
$link_light_color = '#454759';
|
||||
$nav_color = '#ffffff';
|
||||
break;
|
||||
|
||||
case ('purple' || 'purple-dark'):
|
||||
$header_color = '#605ca8';
|
||||
$link_dark_color = '#AC83FF';
|
||||
$link_light_color = '#605ca8';
|
||||
$nav_color = '#ffffff';
|
||||
break;
|
||||
|
||||
case ('yellow' || 'yellow-dark') :
|
||||
$header_color = '#FBCC34';
|
||||
$link_dark_color = '#F0E68C';
|
||||
$link_light_color = '#a69f08';
|
||||
$nav_color = '#ffffff';
|
||||
break;
|
||||
|
||||
case 'contrast':
|
||||
$header_color = '#001F3F';
|
||||
$link_dark_color = '#a6c9ed';
|
||||
$link_light_color = '#2d4863';
|
||||
$nav_color = '#ffffff';
|
||||
break;
|
||||
}
|
||||
|
||||
// Override the header color if the settings have one
|
||||
if ($setting->header_color) {
|
||||
$header_color = $setting->header_color;
|
||||
}
|
||||
|
||||
|
||||
DB::table('settings')->update([
|
||||
'link_light_color' => $link_light_color,
|
||||
'link_dark_color' => $link_dark_color,
|
||||
'nav_link_color' => $nav_color,
|
||||
'header_color' => $header_color]);
|
||||
|
||||
DB::table('users')->whereNull('skin')->update([
|
||||
'link_light_color' => $link_light_color,
|
||||
'link_dark_color' => $link_dark_color,
|
||||
'nav_link_color' => $nav_color]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('settings', function ($table) {
|
||||
$table->dropColumn('link_dark_color');
|
||||
$table->dropColumn('link_light_color');
|
||||
$table->dropColumn('nav_link_color');
|
||||
});
|
||||
|
||||
Schema::table('users', function ($table) {
|
||||
$table->dropColumn('link_dark_color');
|
||||
$table->dropColumn('link_light_color');
|
||||
$table->dropColumn('nav_link_color');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
// Snipe-IT Heroku Startup Script
|
||||
|
||||
// If DB_<value> values are set, ignore parser.
|
||||
if (getenv("DB_DATABASE") || getenv("DB_HOST") || getenv("DB_USERNAME")) {
|
||||
echo "Database Environment variables are manually set. Ignoring add-ins.";
|
||||
} else if (getenv("CLEARDB_DATABASE_URL")) { // ClearDB Add-in
|
||||
echo "Using ClearDB Heroku add-in." . PHP_EOL;
|
||||
set_db(getenv('CLEARDB_DATABASE_URL'));
|
||||
} else if (getenv("JAWSDB_MARIA_URL")) { // JawsDB Maria Add-in
|
||||
echo "Using JawsDB Maria Heroku add-in." . PHP_EOL;
|
||||
set_db(getenv("JAWSDB_MARIA_URL"));
|
||||
} else if (getenv("JAWSDB_MYSQL_URL")) { // JawsDB MySQL Add-in
|
||||
echo "Using JawsDB MySQL Heroku add-in." . PHP_EOL;
|
||||
set_db(getenv("JAWSDB_MYSQL_URL"));
|
||||
}
|
||||
|
||||
function set_db($uri) {
|
||||
file_put_contents('./.env', 'DB_HOST=' . parse_url($uri, PHP_URL_HOST). PHP_EOL, FILE_APPEND);
|
||||
file_put_contents('./.env', 'DB_USERNAME=' . parse_url($uri, PHP_URL_USER). PHP_EOL, FILE_APPEND);
|
||||
file_put_contents('./.env', 'DB_PASSWORD=' . parse_url($uri, PHP_URL_PASS). PHP_EOL, FILE_APPEND);
|
||||
file_put_contents('./.env', 'DB_DATABASE=' . ltrim(parse_url($uri, PHP_URL_PATH), '/'). PHP_EOL, FILE_APPEND);
|
||||
file_put_contents('./.env', 'DB_PREFIX=' . 'null' . PHP_EOL, FILE_APPEND);
|
||||
file_put_contents('./.env', 'DB_DUMP_PATH=' . 'null' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
}
|
||||
|
||||
// If Heroku Redis is setup, let's get it working.
|
||||
if (getenv("REDIS_URL")) { // Heroku Redis
|
||||
echo "Setting up Heroku Redis." . PHP_EOL;
|
||||
$url = getenv("REDIS_URL");
|
||||
file_put_contents('./.env', 'REDIS_HOST=' . parse_url($url, PHP_URL_HOST). PHP_EOL, FILE_APPEND);
|
||||
file_put_contents('./.env', 'REDIS_PASSWORD=' . parse_url($url, PHP_URL_PASS). PHP_EOL, FILE_APPEND);
|
||||
file_put_contents('./.env', 'REDIS_PORT=' . parse_url($url, PHP_URL_PORT). PHP_EOL, FILE_APPEND);
|
||||
}
|
||||
|
||||
// Set up APP_TRUSTED_PROXIES to allow for the Heroku Router
|
||||
// https://devcenter.heroku.com/articles/deploying-symfony4#trusting-the-heroku-router
|
||||
file_put_contents('./.env', 'APP_TRUSTED_PROXIES=10.0.0.0/8' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
// Set up GD
|
||||
file_put_contents('./.env', 'IMAGE_LIB=gd' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
// Set local FILESYSTEM_DISK and PUBLIC_FILESYSTEM_DISK
|
||||
file_put_contents('./.env', 'FILESYSTEM_DISK=local' . PHP_EOL, FILE_APPEND);
|
||||
file_put_contents('./.env', 'PUBLIC_FILESYSTEM_DISK=local_public' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
// Set APP_CIPHER
|
||||
file_put_contents('./.env', 'APP_CIPHER=AES-256-CBC' . PHP_EOL, FILE_APPEND);
|
||||
|
||||
?>
|
||||
@@ -42,7 +42,7 @@
|
||||
"devDependencies": {
|
||||
"all-contributors-cli": "^6.26.1",
|
||||
"axios": "^1.11.0",
|
||||
"jquery": "<3.6.0",
|
||||
"jquery": "^3.7.1",
|
||||
"laravel-mix": "^6.0.49",
|
||||
"lodash": "^4.17.20",
|
||||
"postcss": "^8.5.6",
|
||||
@@ -6678,7 +6678,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jquery": {
|
||||
"version": "3.5.1",
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jquery-knob": {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"devDependencies": {
|
||||
"all-contributors-cli": "^6.26.1",
|
||||
"axios": "^1.11.0",
|
||||
"jquery": "<3.6.0",
|
||||
"jquery": "^3.7.1",
|
||||
"laravel-mix": "^6.0.49",
|
||||
"lodash": "^4.17.20",
|
||||
"postcss": "^8.5.6",
|
||||
|
||||
@@ -1,590 +0,0 @@
|
||||
/* iCheck plugin Minimal skin
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal,
|
||||
.iradio_minimal {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(minimal.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal,
|
||||
.iradio_minimal {
|
||||
background-image: url(minimal@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* red */
|
||||
.icheckbox_minimal-red,
|
||||
.iradio_minimal-red {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(red.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-red {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-red.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-red.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-red.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-red.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-red {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-red.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-red.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-red.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-red.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-red,
|
||||
.iradio_minimal-red {
|
||||
background-image: url(red@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* green */
|
||||
.icheckbox_minimal-green,
|
||||
.iradio_minimal-green {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(green.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-green {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-green.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-green.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-green.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-green.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-green {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-green.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-green.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-green.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-green.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-green,
|
||||
.iradio_minimal-green {
|
||||
background-image: url(green@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* blue */
|
||||
.icheckbox_minimal-blue,
|
||||
.iradio_minimal-blue {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(blue.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-blue {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-blue.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-blue.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-blue.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-blue.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-blue {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-blue.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-blue.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-blue.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-blue.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-blue,
|
||||
.iradio_minimal-blue {
|
||||
background-image: url(blue@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* aero */
|
||||
.icheckbox_minimal-aero,
|
||||
.iradio_minimal-aero {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(aero.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-aero {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-aero.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-aero.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-aero.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-aero.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-aero {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-aero.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-aero.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-aero.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-aero.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-aero,
|
||||
.iradio_minimal-aero {
|
||||
background-image: url(aero@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* grey */
|
||||
.icheckbox_minimal-grey,
|
||||
.iradio_minimal-grey {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(grey.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-grey {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-grey.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-grey.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-grey.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-grey.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-grey {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-grey.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-grey.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-grey.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-grey.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-grey,
|
||||
.iradio_minimal-grey {
|
||||
background-image: url(grey@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* orange */
|
||||
.icheckbox_minimal-orange,
|
||||
.iradio_minimal-orange {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(orange.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-orange {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-orange.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-orange.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-orange.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-orange.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-orange {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-orange.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-orange.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-orange.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-orange.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-orange,
|
||||
.iradio_minimal-orange {
|
||||
background-image: url(orange@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* yellow */
|
||||
.icheckbox_minimal-yellow,
|
||||
.iradio_minimal-yellow {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(yellow.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-yellow {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-yellow.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-yellow.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-yellow.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-yellow.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-yellow {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-yellow.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-yellow.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-yellow.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-yellow.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-yellow,
|
||||
.iradio_minimal-yellow {
|
||||
background-image: url(yellow@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* pink */
|
||||
.icheckbox_minimal-pink,
|
||||
.iradio_minimal-pink {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(pink.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-pink {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-pink.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-pink.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-pink.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-pink.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-pink {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-pink.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-pink.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-pink.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-pink.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-pink,
|
||||
.iradio_minimal-pink {
|
||||
background-image: url(pink@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* purple */
|
||||
.icheckbox_minimal-purple,
|
||||
.iradio_minimal-purple {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(purple.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-purple {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-purple.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-purple.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-purple.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-purple.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-purple {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-purple.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-purple.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-purple.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-purple.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-purple,
|
||||
.iradio_minimal-purple {
|
||||
background-image: url(purple@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, aero
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal-aero,
|
||||
.iradio_minimal-aero {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(aero.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-aero {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-aero.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-aero.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-aero.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-aero.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-aero {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-aero.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-aero.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-aero.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-aero.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-aero,
|
||||
.iradio_minimal-aero {
|
||||
background-image: url(aero@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, blue
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal-blue,
|
||||
.iradio_minimal-blue {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(blue.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-blue {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-blue.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-blue.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-blue.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-blue.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-blue {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-blue.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-blue.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-blue.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-blue.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-blue,
|
||||
.iradio_minimal-blue {
|
||||
background-image: url(blue@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, green
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal-green,
|
||||
.iradio_minimal-green {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(green.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-green {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-green.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-green.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-green.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-green.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-green {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-green.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-green.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-green.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-green.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-green,
|
||||
.iradio_minimal-green {
|
||||
background-image: url(green@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, grey
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal-grey,
|
||||
.iradio_minimal-grey {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(grey.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-grey {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-grey.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-grey.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-grey.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-grey.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-grey {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-grey.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-grey.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-grey.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-grey.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-grey,
|
||||
.iradio_minimal-grey {
|
||||
background-image: url(grey@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, black
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal,
|
||||
.iradio_minimal {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(minimal.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal,
|
||||
.iradio_minimal {
|
||||
background-image: url(minimal@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, orange
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal-orange,
|
||||
.iradio_minimal-orange {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(orange.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-orange {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-orange.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-orange.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-orange.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-orange.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-orange {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-orange.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-orange.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-orange.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-orange.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-orange,
|
||||
.iradio_minimal-orange {
|
||||
background-image: url(orange@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, pink
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal-pink,
|
||||
.iradio_minimal-pink {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(pink.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-pink {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-pink.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-pink.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-pink.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-pink.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-pink {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-pink.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-pink.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-pink.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-pink.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-pink,
|
||||
.iradio_minimal-pink {
|
||||
background-image: url(pink@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, purple
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal-purple,
|
||||
.iradio_minimal-purple {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(purple.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-purple {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-purple.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-purple.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-purple.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-purple.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-purple {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-purple.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-purple.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-purple.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-purple.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-purple,
|
||||
.iradio_minimal-purple {
|
||||
background-image: url(purple@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,59 +0,0 @@
|
||||
/* iCheck plugin Minimal skin, red
|
||||
----------------------------------- */
|
||||
.icheckbox_minimal-red,
|
||||
.iradio_minimal-red {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url(red.png) no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icheckbox_minimal-red {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icheckbox_minimal-red.hover {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
.icheckbox_minimal-red.checked {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
.icheckbox_minimal-red.disabled {
|
||||
background-position: -60px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.icheckbox_minimal-red.checked.disabled {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
.iradio_minimal-red {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
.iradio_minimal-red.hover {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.iradio_minimal-red.checked {
|
||||
background-position: -140px 0;
|
||||
}
|
||||
.iradio_minimal-red.disabled {
|
||||
background-position: -160px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.iradio_minimal-red.checked.disabled {
|
||||
background-position: -180px 0;
|
||||
}
|
||||
|
||||
/* HiDPI support */
|
||||
@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
|
||||
.icheckbox_minimal-red,
|
||||
.iradio_minimal-red {
|
||||
background-image: url(red@2x.png);
|
||||
-webkit-background-size: 200px 20px;
|
||||
background-size: 200px 20px;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,3 +0,0 @@
|
||||
.skin-black .main-header .navbar{background-color:#111}.skin-black .main-header .navbar .nav>li>a{color:#fff}.skin-black .main-header .navbar .nav .open>a,.skin-black .main-header .navbar .nav .open>a:focus,.skin-black .main-header .navbar .nav .open>a:hover,.skin-black .main-header .navbar .nav>.active>a,.skin-black .main-header .navbar .nav>li>a:active,.skin-black .main-header .navbar .nav>li>a:focus,.skin-black .main-header .navbar .nav>li>a:hover,.skin-black .main-header .navbar .sidebar-toggle:hover{background:rgba(0,0,0,.1);color:#f6f6f6}.skin-black .main-header .navbar .sidebar-toggle{color:#fff}.skin-black .main-header .navbar .sidebar-toggle:hover{background-color:#040404}@media (max-width:767px){.skin-black .main-header .navbar .dropdown-menu li.divider{background-color:hsla(0,0%,100%,.1)}.skin-black .main-header .navbar .dropdown-menu li a{color:#333}.skin-black .main-header .navbar .dropdown-menu li a:hover{background:#040404}}.skin-black .main-header li.user-header{background-color:#111}.skin-black .content-header{background:transparent}.skin-black .left-side,.skin-black .main-sidebar,.skin-black .wrapper{background-color:#222d32}.skin-black .user-panel>.info,.skin-black .user-panel>.info>a{color:#fff}.skin-black .sidebar-menu>li.header{background:#1a2226;color:#4b646f}.skin-black .sidebar-menu>li>a{border-left:3px solid transparent}.skin-black .sidebar-menu>li.active>a,.skin-black .sidebar-menu>li:hover>a{background:#1e282c;border-left-color:#111;color:#fff}.skin-black .sidebar-menu>li>.treeview-menu{background:#2c3b41;margin:0 1px}.skin-black .sidebar a{color:#b8c7ce}.skin-black .sidebar a:hover{text-decoration:none}.skin-black .treeview-menu>li>a{color:#8aa4af}.skin-black .treeview-menu>li.active>a,.skin-black .treeview-menu>li>a:hover{color:#fff}.skin-black .sidebar-form{border:1px solid #374850;border-radius:3px;margin:10px}.skin-black .sidebar-form .btn,.skin-black .sidebar-form input[type=text]{background-color:#374850;border:1px solid transparent;box-shadow:none;height:35px;transition:all .3s ease-in-out}.skin-black .sidebar-form input[type=text]{border-bottom-left-radius:2px;border-bottom-right-radius:0;border-top-left-radius:2px;border-top-right-radius:0;color:#666}.skin-black .sidebar-form input[type=text]:focus,.skin-black .sidebar-form input[type=text]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-black .sidebar-form input[type=text]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-black .sidebar-form .btn{border-bottom-left-radius:0;border-bottom-right-radius:2px;border-top-left-radius:0;border-top-right-radius:2px;color:#999}.skin-black.layout-top-nav .main-header>.logo .logo-variant{background-color:none}.btn,.btn:hover{color:#000}.btn .btn-primary:link,.btn.btn-primary,.btn:hover .btn-primary:link,.btn:hover.btn-primary{background-color:#505156;border-color:#fff;color:#fff}.btn:hovera.btn-primary:hover,.btna.btn-primary:hover{background-color:#111;border-color:#1f1f21;color:#fff}.btn.btn-white:hover,.btn.btn-white:link,.btn.btn-white:visited,.btn:hover.btn-white:hover,.btn:hover.btn-white:link,.btn:hover.btn-white:visited{color:#fff}a{color:var(--link)}a:hover{color:var(--hover-link)}a:visited{color:var(--visited-link)}.text-primary{color:#000}:root{--button-default:#000;--button-primary:#000;--button-hover:#000;--header:#111;--text-main:#bbb;--text-sub:#9b9b9b;--link:#black;--visited-link:#111;--hover-link:#999;--nav-link:#fff;--light-link:#fff}.btn-danger.btn-sm.disabled,a.btn-danger:link,a.btn-danger:visited,a.btn-info:link,a.btn-info:visited,a.btn-warning:link,a.btn-warning:visited{color:#fff}.far fa-life-ring{color:var(--link)}.sidebar-toggle-mobile{color:#fff!important}.skin-black .main-header .navbar .nav>li>a{text-decoration:none}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#111}.search-highlight,.search-highlight:hover{background-color:#e9d15b}
|
||||
|
||||
/*# sourceMappingURL=skin-black.css.map*/
|
||||
@@ -1 +0,0 @@
|
||||
.skin-black .main-header .navbar{background-color:#111}.skin-black .main-header .navbar .nav>li>a{color:#fff}.skin-black .main-header .navbar .nav .open>a,.skin-black .main-header .navbar .nav .open>a:focus,.skin-black .main-header .navbar .nav .open>a:hover,.skin-black .main-header .navbar .nav>.active>a,.skin-black .main-header .navbar .nav>li>a:active,.skin-black .main-header .navbar .nav>li>a:focus,.skin-black .main-header .navbar .nav>li>a:hover,.skin-black .main-header .navbar .sidebar-toggle:hover{background:rgba(0,0,0,.1);color:#f6f6f6}.skin-black .main-header .navbar .sidebar-toggle{color:#fff}.skin-black .main-header .navbar .sidebar-toggle:hover{background-color:#040404}@media (max-width:767px){.skin-black .main-header .navbar .dropdown-menu li.divider{background-color:hsla(0,0%,100%,.1)}.skin-black .main-header .navbar .dropdown-menu li a{color:#333}.skin-black .main-header .navbar .dropdown-menu li a:hover{background:#040404}}.skin-black .main-header li.user-header{background-color:#111}.skin-black .content-header{background:0 0}.skin-black .left-side,.skin-black .main-sidebar,.skin-black .wrapper{background-color:#222d32}.skin-black .user-panel>.info,.skin-black .user-panel>.info>a{color:#fff}.skin-black .sidebar-menu>li.header{background:#1a2226;color:#4b646f}.skin-black .sidebar-menu>li>a{border-left:3px solid transparent}.skin-black .sidebar-menu>li.active>a,.skin-black .sidebar-menu>li:hover>a{background:#1e282c;border-left-color:#111;color:#fff}.skin-black .sidebar-menu>li>.treeview-menu{background:#2c3b41;margin:0 1px}.skin-black .sidebar a{color:#b8c7ce}.skin-black .sidebar a:hover{text-decoration:none}.skin-black .treeview-menu>li>a{color:#8aa4af}.skin-black .treeview-menu>li.active>a,.skin-black .treeview-menu>li>a:hover{color:#fff}.skin-black .sidebar-form{border:1px solid #374850;border-radius:3px;margin:10px}.skin-black .sidebar-form .btn,.skin-black .sidebar-form input[type=text]{background-color:#374850;border:1px solid transparent;box-shadow:none;height:35px;transition:all .3s ease-in-out}.skin-black .sidebar-form input[type=text]{border-bottom-left-radius:2px;border-bottom-right-radius:0;border-top-left-radius:2px;border-top-right-radius:0;color:#666}.skin-black .sidebar-form input[type=text]:focus,.skin-black .sidebar-form input[type=text]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-black .sidebar-form input[type=text]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-black .sidebar-form .btn{border-bottom-left-radius:0;border-bottom-right-radius:2px;border-top-left-radius:0;border-top-right-radius:2px;color:#999}.skin-black.layout-top-nav .main-header>.logo .logo-variant{background-color:none}.btn,.btn:hover{color:#000}.btn .btn-primary:link,.btn.btn-primary,.btn:hover .btn-primary:link,.btn:hover.btn-primary{background-color:#505156;border-color:#fff;color:#fff}.btn:hovera.btn-primary:hover,.btna.btn-primary:hover{background-color:#111;border-color:#1f1f21;color:#fff}.btn.btn-white:hover,.btn.btn-white:link,.btn.btn-white:visited,.btn:hover.btn-white:hover,.btn:hover.btn-white:link,.btn:hover.btn-white:visited{color:#fff}a{color:var(--link)}a:hover{color:var(--hover-link)}a:visited{color:var(--visited-link)}.text-primary{color:#000}:root{--button-default:#000;--button-primary:#000;--button-hover:#000;--header:#111;--text-main:#bbb;--text-sub:#9b9b9b;--link:#black;--visited-link:#111;--hover-link:#999;--nav-link:#fff;--light-link:#fff}.btn-danger.btn-sm.disabled,a.btn-danger:link,a.btn-danger:visited,a.btn-info:link,a.btn-info:visited,a.btn-warning:link,a.btn-warning:visited{color:#fff}.far fa-life-ring{color:var(--link)}.sidebar-toggle-mobile{color:#fff!important}.skin-black .main-header .navbar .nav>li>a{text-decoration:none}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#111}.search-highlight,.search-highlight:hover{background-color:#e9d15b}
|
||||
@@ -1,3 +0,0 @@
|
||||
.skin-blue .main-header .navbar{background-color:#3c8dbc}.skin-blue .main-header .navbar .nav>li>a{color:#fff}.skin-blue .main-header .navbar .nav .open>a,.skin-blue .main-header .navbar .nav .open>a:focus,.skin-blue .main-header .navbar .nav .open>a:hover,.skin-blue .main-header .navbar .nav>.active>a,.skin-blue .main-header .navbar .nav>li>a:active,.skin-blue .main-header .navbar .nav>li>a:focus,.skin-blue .main-header .navbar .nav>li>a:hover,.skin-blue .main-header .navbar .sidebar-toggle:hover{background:rgba(0,0,0,.1);color:#f6f6f6}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue .main-header .navbar .dropdown-menu li.divider{background-color:hsla(0,0%,100%,.1)}.skin-blue .main-header .navbar .dropdown-menu li a{color:#333}.skin-blue .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue .main-header li.user-header{background-color:#3c8dbc}.skin-blue .content-header{background:transparent}.skin-blue .left-side,.skin-blue .main-sidebar,.skin-blue .wrapper{background-color:#222d32}.skin-blue .user-panel>.info,.skin-blue .user-panel>.info>a{color:#fff}.skin-blue .sidebar-menu>li.header{background:#1a2226;color:#4b646f}.skin-blue .sidebar-menu>li>a{border-left:3px solid transparent}.skin-blue .sidebar-menu>li.active>a,.skin-blue .sidebar-menu>li:hover>a{background:#1e282c;border-left-color:#3c8dbc;color:#fff}.skin-blue .sidebar-menu>li>.treeview-menu{background:#2c3b41;margin:0 1px}.skin-blue .sidebar a{color:#b8c7ce}.skin-blue .sidebar a:hover{text-decoration:none}.skin-blue .treeview-menu>li>a{color:#8aa4af}.skin-blue .treeview-menu>li.active>a,.skin-blue .treeview-menu>li>a:hover{color:#fff}.skin-blue .sidebar-form{border:1px solid #374850;border-radius:3px;margin:10px}.skin-blue .sidebar-form .btn,.skin-blue .sidebar-form input[type=text]{background-color:#374850;border:1px solid transparent;box-shadow:none;height:35px;transition:all .3s ease-in-out}.skin-blue .sidebar-form input[type=text]{border-bottom-left-radius:2px;border-bottom-right-radius:0;border-top-left-radius:2px;border-top-right-radius:0;color:#666}.skin-blue .sidebar-form input[type=text]:focus,.skin-blue .sidebar-form input[type=text]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue .sidebar-form input[type=text]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue .sidebar-form .btn{border-bottom-left-radius:0;border-bottom-right-radius:2px;border-top-left-radius:0;border-top-right-radius:2px;color:#999}.skin-blue.layout-top-nav .main-header>.logo .logo-variant{background-color:unset}.btn .btn-primary:link,.btn.btn-primary,.btn:hover .btn-primary:link,.btn:hover.btn-primary,btn-sm .btn-primary:link,btn-sm.btn-primary{background-color:#307095;border-color:#23536f;color:#fff!important}.btn:hovera.btn-primary:hover,.btna.btn-primary:hover,btn-sma.btn-primary:hover{background-color:#23536f;border-color:#23536f;color:#fff}.btn.btn-white:link,.btn:hover.btn-white:link,btn-sm.btn-white:link{background-color:#307095;color:#fff}.btn.btn-white:hover,.btn.btn-white:visited,.btn:hover.btn-white:hover,.btn:hover.btn-white:visited,btn-sm.btn-white:hover,btn-sm.btn-white:visited{background-color:#173648;color:#fff}.btn-danger,.btn-danger:link,.btn-danger:visited,.btn-warning,.btn-warning:link,.btn-warning:visited,a.btn-danger:hover,a.btn-warning:hover{color:#fff}.btn-default:link,.btn-default:visited,a.btn-default:hover{color:#505156}:root{--button-default:#505156;--button-primary:#1d455b;--button-hover:#173648;--header:#3c8dbc;--text-main:#bbb;--text-sub:#9b9b9b;--link:#296282;--visited-link:#5fa4cc;--hover-link:#86bad8;--nav-link:#fff;--light-link:#fff}a.btn-danger:link,a.btn-danger:visited,a.btn-info:link,a.btn-info:visited,a.btn-warning:link,a.btn-warning:visited{color:#fff}a:link{color:var(--link)}a:visited{color:var(--visited-link)}a:hover{color:var(--hover-link)}.text-primary{color:#23536f}.far fa-life-ring{color:var(--link)}.fixed-table-container tbody .selected td{background-color:#fff8af}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#3c8dbc}.search-highlight,.search-highlight:hover{background-color:#e9d15b}a.settings_button:hover,a.settings_button:link,a.settings_button:visited{color:#3c8dbc}a.label.label-default:link{color:#307095}a.label.label-default:visited{color:#23536f}a.label.label-default:hover{background-color:#bbb;color:#296282}
|
||||
|
||||
/*# sourceMappingURL=skin-blue.css.map*/
|
||||