Merge pull request #1277 from snipe/custom_fields

Basic custom fields support - needs UI refinements
This commit is contained in:
snipe
2015-11-25 19:14:53 -08:00
31 changed files with 3417 additions and 43 deletions
+133
View File
@@ -0,0 +1,133 @@
<?php
class CustomFieldsController extends \BaseController {
/**
* Display a listing of the resource.
*
* @return Response
*/
public function getIndex()
{
//
return View::make("backend.custom_fields.index")->with("custom_fieldsets",CustomFieldset::all())->with("custom_fields",CustomField::all());
}
/**
* Show the form for creating a new resource.
*
* @return Response
*/
public function getCreate()
{
//
return View::make("backend.custom_fields.create");
}
/**
* Store a newly created resource in storage.
*
* @return Response
*/
public function postIndex()
{
//
$cfset=new CustomFieldset(["name" => Input::get("name")]);
$cfset->save();
return Redirect::to("/custom_fieldsets/".$cfset->id); //redirect(["asdf" => "alskdjf"]);
}
public function postAssociate($id)
{
print "ID is: $id";
$set=CustomFieldset::find($id);
$results=$set->fields()->attach(Input::get('field_id'),["required" => (Input::get('required') == "on"),"order" => Input::get('order')]);
//return "I assoced it. Results: $results";
return Redirect::to("/custom_fieldsets/".$id); //redirect(["asdf" => "alskdjf"]);
}
public function getCreateField()
{
return View::make("backend.custom_fields.create_field");
}
public function postCreateField()
{
$field=new CustomField(["name" => Input::get("name"),"element" => Input::get("element")]);
if(!in_array(Input::get('format'),["ALPHA","NUMERIC","MAC","IP"])) {
$field->format=Input::get("custom_format");
} else {
$field->format=Input::get('format');
}
$results=$field->save();
//return "postCreateField: $results";
if ($results) {
return Redirect::to("/custom_fieldsets/");
} else {
return Redirect::to("/custom_fieldsets/create-field");
}
}
/**
* Display the specified resource.
*
* @param int $id
* @return Response
*/
public function missingMethod($parameters = array())
{
$id=$parameters[0];
$cfset=CustomFieldset::find($id);
//print_r($parameters);
//
$maxid=0;
foreach($cfset->fields AS $field) {
if($field->pivot->order > $maxid) {
$maxid=$field->pivot->order;
}
}
return View::make("backend.custom_fields.show")->with("custom_fieldset",$cfset)->with("maxid",$maxid+1);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param int $id
* @return Response
*/
public function update($id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return Response
*/
public function destroy($id)
{
//
}
}
+34 -6
View File
@@ -31,6 +31,7 @@ use Paginator;
use Manufacturer; //for embedded-create
use Artisan;
use Symfony\Component\Console\Output\BufferedOutput;
use CustomField;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -268,9 +269,26 @@ class AssetsController extends AdminController
else if (!Company::isCurrentUserHasAccess($asset)) {
return Redirect::to('hardware')->with('error', Lang::get('general.insufficient_permissions'));
}
$input=Input::all();
// return "INPUT IS: <pre>".print_r($input,true)."</pre>";
$rules=$asset->validationRules($assetId);
if($asset->model->fieldset)
{
foreach($asset->model->fieldset->fields AS $field) {
$input[$field->db_column_name()]=$input['fields'][$field->db_column_name()];
$asset->{$field->db_column_name()}=$input[$field->db_column_name()];
}
$rules+=$asset->model->fieldset->validation_rules();
unset($input['fields']);
}
//return "Rules: <pre>".print_r($rules,true)."</pre>";
//attempt to validate
$validator = Validator::make(Input::all(), $asset->validationRules($assetId));
$validator = Validator::make($input, $rules );
$custom_errors=[];
if ($validator->fails())
{
@@ -290,7 +308,7 @@ class AssetsController extends AdminController
if (e(Input::get('warranty_months')) == '') {
$asset->warranty_months = NULL;
} else {
$asset->warranty_months = e(Input::get('warranty_months'));
$asset->warranty_months = e(Input::get('warranty_months'));
}
if (e(Input::get('purchase_cost')) == '') {
@@ -324,7 +342,7 @@ class AssetsController extends AdminController
}
$checkModel = Config::get('app.url').'/api/models/'.e(Input::get('model_id')).'/check';
$asset->mac_address = ($checkModel == true) ? e(Input::get('mac_address')) : NULL;
//$asset->mac_address = ($checkModel == true) ? e(Input::get('mac_address')) : NULL;
// Update the asset data
$asset->name = e(Input::get('name'));
@@ -1200,7 +1218,7 @@ class AssetsController extends AdminController
{
$assets = Asset::select('assets.*')->with('model','assigneduser','assigneduser.userloc','assetstatus','defaultLoc','assetlog','model','model.category','assetstatus','assetloc', 'company')
$assets = Asset::select('assets.*')->with('model','assigneduser','assigneduser.userloc','assetstatus','defaultLoc','assetlog','model','model.category','model.fieldset','assetstatus','assetloc', 'company')
->Hardware();
if (Input::has('search')) {
@@ -1263,6 +1281,12 @@ class AssetsController extends AdminController
'location',
'image',
];
$all_custom_fields=CustomField::all(); //used as a 'cache' of custom fields throughout this page load
foreach($all_custom_fields AS $field) {
$allowed_columns[]=$field->db_column_name();
}
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array(Input::get('sort'), $allowed_columns) ? Input::get('sort') : 'asset_tag';
@@ -1313,7 +1337,7 @@ class AssetsController extends AdminController
}
}
$rows[] = array(
$row = array(
'checkbox' =>'<div class="text-center"><input type="checkbox" name="edit_asset['.$asset->id.']" class="one_required"></div>',
'id' => $asset->id,
'image' => ($asset->image!='') ? '<img src="'.Config::get('app.url').'/uploads/assets/'.$asset->image.'" height=50 width=50>' : (($asset->model->image!='') ? '<img src="'.Config::get('app.url').'/uploads/models/'.$asset->model->image.'" height=40 width=50>' : ''),
@@ -1332,7 +1356,11 @@ class AssetsController extends AdminController
'change' => ($inout) ? $inout : '',
'actions' => ($actions) ? $actions : '',
'companyName' => is_null($asset->company) ? '' : e($asset->company->name)
);
);
foreach($all_custom_fields AS $field) {
$row[$field->db_column_name()]=$asset->{$field->db_column_name()};
}
$rows[]=$row;
}
$data = array('total'=>$assetCount, 'rows'=>$rows);
+2 -1
View File
@@ -239,7 +239,8 @@ class ModelsController extends AdminController
$model->modelno = e(Input::get('modelno'));
$model->manufacturer_id = e(Input::get('manufacturer_id'));
$model->category_id = e(Input::get('category_id'));
$model->show_mac_address = e(Input::get('show_mac_address', '0'));
//$model->show_mac_address = e(Input::get('show_mac_address', '0'));
$model->fieldset_id = e(Input::get('custom_fieldset'));
if (Input::file('image')) {
$image = Input::file('image');
@@ -0,0 +1,36 @@
<?php
//use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCustomFieldsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('custom_fields', function ($table) {
$table->increments('id');
$table->string('name');
$table->string('format');
$table->string('element');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::drop('custom_fields');
}
}
@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCustomFieldCustomFieldset extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('custom_field_custom_fieldset', function(Blueprint $table)
{
$table->integer('custom_field_id');
$table->integer('custom_fieldset_id');
$table->integer('order');
$table->boolean('required');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('custom_field_custom_fieldset');
}
}
@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCustomFieldsets extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('custom_fieldsets', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
//
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('custom_fieldsets');
}
}
@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddFieldsetIdToAssets extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('models', function (Blueprint $table) {
$table->integer('fieldset_id')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('models',function (Blueprint $table) {
$table->dropColumn('fieldset_id');
});
}
}
@@ -0,0 +1,56 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class MigrateMacAddress extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
$f2=new CustomFieldset(['name' => "Asset with MAC Address"]);
if(!$f2->save()) {
throw new Exception("couldn't save customfieldset");
}
$macid=DB::table('custom_fields')->insertGetId([
'name' => "MAC Address",
'format' => CustomField::$PredefinedFormats['MAC'],
'element'=>'text']);
if(!$macid) {
throw new Exception("Can't save MAC Custom field: $macid");
}
$f2->fields()->attach($macid,['required' => false, 'order' => 1]);
Model::where(["show_mac_address" => true])->update(["fieldset_id"=>$f2->id]);
DB::statement("ALTER TABLE assets CHANGE mac_address _snipeit_mac_address varchar(255)");
$ans=Schema::table("models",function (Blueprint $table) {
$table->renameColumn('show_mac_address','deprecated_mac_address');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
$f=CustomFieldset::where(["name" => "Asset with MAC Address"])->first();
$f->fields()->delete();
$f->delete();
Schema::table("models",function(Blueprint $table) {
$table->renameColumn("deprecated_mac_address","show_mac_address");
});
DB::statement("ALTER TABLE assets CHANGE _snipeit_mac_address mac_address varchar(255)");
}
}
+21 -7
View File
@@ -5,13 +5,16 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
function ParseFloat($floatString){
// use comma for thousands until local info is property used
$LocaleInfo = localeconv();
$floatString = str_replace("," , "", $floatString);
$floatString = str_replace($LocaleInfo["decimal_point"] , ".", $floatString);
return floatval($floatString);
if(!function_exists("ParseFloat")) {
//this may be only necessary to run tests?
function ParseFloat($floatString){
// use comma for thousands until local info is property used
$LocaleInfo = localeconv();
$floatString = str_replace("," , "", $floatString);
$floatString = str_replace($LocaleInfo["decimal_point"] , ".", $floatString);
return floatval($floatString);
}
}
function modelList() {
@@ -86,6 +89,17 @@ function usersList() {
return $users_list;
}
function customFieldsetList() {
$customfields=CustomFieldset::lists('name','id');
return array('' => Lang::get('general.no_custom_field')) + $customfields;
}
function predefined_formats() {
$keys=array_keys(CustomField::$PredefinedFormats);
$stuff=array_combine($keys,$keys);
return $stuff+["" => "Custom Format..."];
}
function barcodeDimensions ($barcode_type = 'QRCODE') {
if ($barcode_type == 'C128') {
$size['height'] = '-1';
+3
View File
@@ -696,6 +696,9 @@ return false;
->orWhere('order_number','LIKE','%'.$search.'%')
->orWhere('notes','LIKE','%'.$search.'');
}
foreach(CustomField::all() AS $field) {
$query->orWhere($field->db_column_name(),'LIKE',"%$search%");
}
});
}
+99
View File
@@ -0,0 +1,99 @@
<?php
class CustomField extends Elegant
{
public $guarded=["id"];
public static $PredefinedFormats=[
"ANY" => "",
"ALPHA" => "[a-zA-Z]*",
"NUMERIC" => "[0-9]*",
"MAC" => "[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}",
"IP" => "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])"
];
public static $table_name="assets";
public static function name_to_db_name($name)
{
return "_snipeit_".preg_replace("/\s/","_",strtolower($name));
}
public static function boot()
{
self::creating(function ($custom_field) {
if(in_array($custom_field->db_column_name(),Schema::getColumnListing(DB::getTablePrefix().CustomField::$table_name))) {
//field already exists when making a new custom field; fail.
return false;
}
return DB::statement("ALTER TABLE ".DB::getTablePrefix().CustomField::$table_name." ADD COLUMN (".$custom_field->db_column_name()." TEXT)");
});
self::updating(function ($custom_field) {
//print(" SAVING CALLBACK FIRING!!!!! ");
if($custom_field->isDirty("name")) {
//print("DIRTINESS DETECTED!");
//$fields=array_keys($custom_field->getAttributes());
//;
//add timestamp fields, add id column
//array_push($fields,$custom_field->getKeyName());
/*if($custom_field::timestamps) {
}*/
//print("Fields are: ".print_r($fields,true));
if(in_array($custom_field->db_column_name(),Schema::getColumnListing(CustomField::$table_name))) {
//field already exists when renaming a custom field
return false;
}
return DB::statement("UPDATE ".CustomField::$table_name." RENAME ".self::name_to_db_name($custom_field->get_original("name"))." TO ".$custom_field->db_column_name());
}
return true;
});
}
/*public static function boot() {
parent::boot();
self::saving(function ($data) {
print("DOES THIS AT LEAST CATCH IT?!");
self::check_db_name($data);
});
}*/
public function fieldset() {
return $this->belongsToMany('CustomFieldset'); //?!?!?!?!?!?
}
//public function
//need helper to go from regex->English
//need helper to go from English->regex
//need helper for save() stuff - basically to alter table for the fields in question
public function check_format($value) {
return preg_match('/^'.$this->attributes['format'].'$/',$value)===1;
}
public function db_column_name() {
return self::name_to_db_name($this->name);
}
//mutators for 'format' attribute
public function getFormatAttribute($value) {
foreach(self::$PredefinedFormats AS $name => $pattern) {
if($pattern===$value) {
return $name;
}
}
return $value;
}
public function setFormatAttribute($value) {
if(isset(self::$PredefinedFormats[$value])) {
$this->attributes['format']=self::$PredefinedFormats[$value];
} else {
$this->attributes['format']=$value;
}
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
class CustomFieldset extends Elegant
{
protected $guarded=["id"];
public $timestamps=false;
public function fields() {
return $this->belongsToMany('CustomField')->withPivot(["required","order"])->orderBy("pivot_order");
}
public function validation_rules()
{
$rules=[];
foreach($this->fields AS $field) {
$rule=[];
if($field->pivot->required) {
$rule[]="required";
}
array_push($rule,"regex:/".$field->attributes['format']."/");
$rules[$field->db_column_name()]=$rule;
}
return $rules;
}
//requiredness goes *here*
//sequence goes here?
}
+3
View File
@@ -1,5 +1,8 @@
<?php
//use Eloquent;
use Illuminate\Database\Eloquent\Model as Eloquent;
class Elegant extends Eloquent
{
protected $rules = array();
+7
View File
@@ -1,5 +1,7 @@
<?php
//use CustomField;
class Model extends Elegant
{
use SoftDeletingTrait;
@@ -40,6 +42,11 @@ class Model extends Elegant
{
return $this->belongsTo('Manufacturer','manufacturer_id');
}
public function fieldset()
{
return $this->belongsTo('CustomFieldset','fieldset_id');
}
/**
* -----------------------------------------------
+7
View File
@@ -140,6 +140,13 @@
} );
} );
# Custom fieldset
//Route::get('/custom_fieldsets/{id}','CustomFieldsController@show');
//Route::get('/custom_fieldsets/create','CustomFieldsController@getCreate');
Route::post('/custom_fieldsets/{id}/associate','CustomFieldsController@postAssociate');
Route::controller('/custom_fieldsets','CustomFieldsController' );
/*
|--------------------------------------------------------------------------
| Asset Routes
+78
View File
@@ -0,0 +1,78 @@
<?php
//require '/var/www/html/app/models/CustomField.php';
//use Illuminate\Foundation\Testing\
class CustomFieldTest extends TestCase //PHPUnit_Framework_TestCase
{
public function testConstructor() {
$f=new CustomField();
}
public function testBadIP() {
$f=new CustomField();
$f->name="test 1";
$f->format="IP";
$f->element="text";
$f->save();
$this->assertFalse($f->check_format("300.2.3.4"));
}
public function testGoodIP() {
$f=new CustomField();
$f->name="test 1";
$f->format="IP";
$f->element="text";
$f->save();
$this->assertTrue($f->check_format("1.2.3.4"));
}
public function testFormat() {
$f=new CustomField();
$f->name="test 1";
$f->format="IP";
$f->element="text";
$f->save();
//print_r($f->attributes);
//print($f);
//print("Uhm, format is: ".$f->attributes['format']);
//print("Lemme try this: ".$f->getAttribute('format'));
//print("Moar: ".print_r($f->getAttributes(),true));
$this->assertEquals($f->getAttributes()['format'],CustomField::$PredefinedFormats['IP']); //this seems undocumented...
$this->assertEquals($f->format,"IP");
}
public function testDbName() {
$f=new CustomField();
$f->name="An Example Name";
$this->assertEquals($f->db_column_name(),"an_example_name");
}
public function testValidation() {
$f=new CustomField();
$f->name='Id';
$f->format='IP';
$f->element="text";
/*$this->assertDoesntThrow(function () {
$f->save();
});*/
$this->assertFalse(CustomField::saving($f)); //horrible hacky workaround to even problems
//for Laravel testing. Blech.
$g=new CustomField();
$g->name='totally_unique_name';
$g->format='IP';
$g->element="text";
//$this->assertTrue($g->validate($g->toArray()));
$this->assertTrue(CustomField::saving($g));
/*$this->assertThrows(function () {
$f->save();
});*/
}
}
+5
View File
@@ -24,3 +24,8 @@ Validator::extend('unique_multiple', function ($attribute, $value, $parameters)
// Validation result will be false if any rows match the combination
return ($query->count() == 0);
});
Validator::extend('unique_column',function ($attribute,$value,$parameters) {
return false;
});
@@ -0,0 +1,10 @@
@extends('backend/layouts/default')
@section('content')
<?= Form::open(['url' => '/custom_fieldsets']) ?>
Name: <input type='text' name='name'><br />
<input type='submit'>
</form>
<br><a href='/custom_fieldsets'>Back to Custom Fieldset List</a>
@stop
@@ -0,0 +1,13 @@
@extends('backend/layouts/default')
@section('content')
{{ Form::open(["url" =>"/custom_fieldsets/create-field"])}}
Name: {{ Form::text("name")}}<br>
type: {{ Form::select("element",["text" => "Text Box"])}}<br>
format: {{ Form::select("format",predefined_formats(),"ANY") }}
Custom Format (if selected): {{ Form::text("custom_format") }}<br>
<input type='submit'>
{{ Form::close() }}
<br><a href='/custom_fieldsets'>Back to Custom Fieldset List</a>
@stop
@@ -0,0 +1,21 @@
@extends('backend/layouts/default')
@section('content')
<?
?>
<h2>Fieldsets</h2>
<ul>
@foreach($custom_fieldsets AS $fieldset)
<li><a href='/custom_fieldsets/{{$fieldset->id}}'>{{{$fieldset->name}}}</li>
@endforeach
</ul>
<a href='/custom_fieldsets/create'>New Fieldset</a><br>
<h2>Custom Field Definitions</h2>
<ul>
@foreach($custom_fields AS $field)
<li>{{{$field->name}}}, {{{$field->format}}}</li>
@endforeach
</ul>
<a href='/custom_fieldsets/create-field'>New Field</a>
@stop
@@ -0,0 +1,16 @@
@extends('backend/layouts/default')
@section('content')
<h2>Fieldset</h2>
{{{ $custom_fieldset->name }}}
<ul>
@foreach($custom_fieldset->fields AS $field)
<li>{{$field->pivot->order}}) {{$field->name}}, {{$field->format}}, {{$field->pivot->required ? "REQUIRED" : "OPTIONAL"}}</li>
@endforeach
</ul>
{{ Form::open(['url' => '/custom_fieldsets/'.$custom_fieldset->id.'/associate']) }}
{{ Form::checkbox("required","on") }}Required?
{{ Form::text("order",$maxid)}}
{{ Form::select("field_id",["" => "Add New Field to Fieldset"] + CustomField::lists("name","id"),"",["onchange" => "document.forms[0].submit()"]) }}
<br><a href='/custom_fieldsets'>Back to Custom Fieldset List</a>
@stop
+15 -2
View File
@@ -188,7 +188,7 @@
</div>
<!-- MAC Address -->
<div id="mac_address" class="form-group {{ $errors->has('mac_address') ? ' has-error' : '' }}" style="display:none;">
<div id="mac_address" class="form-group {{ $errors->has('mac_address') ? ' has-error' : '' }}" > <!-- style="display:none;" -->
<label for="mac_address" class="col-md-2 control-label">@lang('admin/hardware/form.mac_address')</label>
<div class="col-md-7 col-sm-12">
<input class="form-control" type="text" name="mac_address" id="mac_address" value="{{{ Input::old('mac_address', $asset->mac_address) }}}" />
@@ -287,7 +287,7 @@
{{ $errors->first('assigned_to', '<br><span class="alert-msg"><i class="fa fa-times"></i> :message</span>') }}
</div>
</div>
@endif
@endif
<!-- Notes -->
<div class="form-group {{ $errors->has('notes') ? ' has-error' : '' }}">
@@ -318,6 +318,19 @@
</div>
</div>
</div>
<!-- Custom Fields -->
@if($asset->model && $asset->model->fieldset)
<h1>Custom Fields</h1>
@foreach($asset->model->fieldset->fields AS $field)
<div class="form-group">
<label for="idunno" class="col-md-2 control-label">{{{ $field->name }}}</label>
<div class="col-md-7 col-sm-12">
<input type="text" value="{{{ Input::old('fields[{{$field->db_column_name()}}]',$asset->{$field->db_column_name()}) }}}" name="fields[{{{ $field->db_column_name() }}}]">
</div>
</div>
@endforeach
@endif
<!-- Image -->
+3 -2
View File
@@ -72,7 +72,6 @@
data-cookie-id-table="assetTable-{{ Config::get('version.hash_version') }}">
<thead>
<tr>
<th data-class="hidden-xs" data-switchable="false" data-searchable="false" data-sortable="false" data-field="checkbox"><div class="text-center"><input type="checkbox" id="checkAll" style="padding-left: 0px;"></div></th>
<th data-sortable="true" data-field="id" data-visible="false">@lang('general.id')</th>
<th data-field="companyName" data-searchable="true" data-sortable="true" data-switchable="true">@lang('general.company')</th>
@@ -89,6 +88,9 @@
<th data-sortable="true" data-searchable="true" data-field="order_number">@lang('admin/hardware/form.order')</th>
<th data-sortable="true" data-searchable="true" data-field="last_checkout">@lang('admin/hardware/table.checkout_date')</th>
<th data-sortable="true" data-field="expected_checkin" data-searchable="true">@lang('admin/hardware/form.expected_checkin')</th>
@foreach(CustomField::all() AS $field)
<th data-sortable="true" data-field="{{$field->db_column_name()}}">{{{$field->name}}}</th>
@endforeach
<th data-switchable="false" data-searchable="false" data-sortable="false" data-field="change">@lang('admin/hardware/table.change')</th>
<th data-switchable="false" data-searchable="false" data-sortable="false" data-field="actions" >@lang('table.actions')</th>
</tr>
@@ -105,7 +107,6 @@
</tr>
</tfoot>
</table>
{{ Form::close() }}
</div>
+11 -6
View File
@@ -70,12 +70,6 @@
@endif
@if ($asset->mac_address!='')
<div class="col-md-12" style="padding-bottom: 5px;"><strong>@lang('admin/hardware/form.mac_address'):</strong>
{{{ $asset->mac_address }}}
</div>
@endif
@if ($asset->model->manufacturer)
<div class="col-md-12" style="padding-bottom: 5px;"><strong>@lang('admin/hardware/form.manufacturer'): </strong>
<a href="{{ route('update/manufacturer', $asset->model->manufacturer->id) }}">
@@ -170,6 +164,17 @@
</div>
@endif
@if ($asset->model->fieldset)
<hr>
<div class="col-md-12" style="padding-bottom: 5px;"><strong>FIELDSET:</strong>
{{{ $asset->model->fieldset->name }}}</div>
@foreach($asset->model->fieldset->fields as $field)
<div class="col-md-12" style="padding-bottom: 5px;"><strong>{{{ $field->name }}}:</strong>
{{{ $asset->{$field->db_column_name()} }}}
</div>
@endforeach
<hr>
@endif
@if ($asset->expected_checkin!='')
<div class="col-md-12" style="padding-bottom: 5px;">
<strong>@lang('admin/hardware/form.expected_checkin')</strong>
@@ -249,6 +249,11 @@
<i class="fa fa-download fa-fw"></i> @lang('admin/settings/general.backups')
</a>
</li>
<li{{ (Request::is('custom_fieldsets*') ? ' class="active"' : '') }}>
<a href="{{ URL::to('custom_fieldsets') }}">
<i class="fa fa-wrench fa-fw"></i> Custom Fields?
</a>
</li>
<li class="divider"></li>
<li>
<a href="{{ route('app') }}">
+19 -18
View File
@@ -52,17 +52,17 @@
</div>
</div>
<div class="form-group {{ $errors->has('manufacturer_id') ? ' has-error' : '' }}">
<label for="manufacturer_id" class="col-md-2 control-label">@lang('general.manufacturer')
<i class='fa fa-asterisk'></i></label>
</label>
<div class="col-md-7">
{{ Form::select('manufacturer_id', $manufacturer_list , Input::old('manufacturer_id', $model->manufacturer_id), array('class'=>'select2', 'style'=>'width:350px')) }}
{{ $errors->first('manufacturer_id', '<br><span class="alert-msg"><i class="fa fa-times"></i> :message</span>') }}
</div>
</div>
<div class="form-group {{ $errors->has('manufacturer_id') ? ' has-error' : '' }}">
<label for="manufacturer_id" class="col-md-2 control-label">@lang('general.manufacturer')
<i class='fa fa-asterisk'></i></label>
</label>
<div class="col-md-7">
{{ Form::select('manufacturer_id', $manufacturer_list , Input::old('manufacturer_id', $model->manufacturer_id), array('class'=>'select2', 'style'=>'width:350px')) }}
{{ $errors->first('manufacturer_id', '<br><span class="alert-msg"><i class="fa fa-times"></i> :message</span>') }}
</div>
</div>
<!-- Category -->
<!-- Category -->
<div class="form-group {{ $errors->has('category_id') ? ' has-error' : '' }}">
<label for="category_id" class="col-md-2 control-label">@lang('general.category')
<i class='fa fa-asterisk'></i></label>
@@ -107,14 +107,15 @@
</div>
</div>
<div class="form-group {{ $errors->has('eol') ? ' has-error' : '' }}">
<div class="checkbox col-md-offset-2">
<label>
{{ Form::checkbox('show_mac_address', '1', Input::old('show_mac_address', $model->show_mac_address)) }}
@lang('admin/models/general.show_mac_address')
</label>
</div>
</div>
<!-- Custom Fieldset -->
<div class="form-group {{ $errors->has('custom_fieldset') ? ' has-error' : '' }}">
<label for="custom_fieldset" class="col-md-2 control-label">@lang('admin/models/general.choose_fieldset')</label>
<div class="col-md-7">
{{ Form::select('custom_fieldset', customFieldsetList(),Input::old('custom_fieldset', $model->fieldset_id), array('class'=>'select2', 'style'=>'width:350px')) }}
{{ $errors->first('custom_fieldset', '<br><span class="alert-msg"><i class="fa fa-times"></i> :message</span>') }}
</label>
</div>
</div>
<!-- Image -->
@if ($model->image)
+20
View File
@@ -0,0 +1,20 @@
# Docker Environment File
#Database Variables
MYSQL_DATABASE=snipeit
MYSQL_USER=snipeit
MYSQL_PASSWORD=tinglewingler
#Email Variables
MAIL_PORT_587_TCP_ADDR=smtp.mandrillapp.com
MAIL_PORT_587_TCP_PORT=587
MAIL_ENV_FROM_ADDR=uberbrady@gmail.com
MAIL_ENV_FROM_NAME=Brady Wetherington
MAIL_ENV_ENCRYPTION=tcp
MAIL_ENV_USERNAME=uberbrady@gmail.com
MAIL_ENV_PASSWORD=N7AqLufTZMULWHWYwJ0ZCw
#SNIPE-IT Variables
SNIPEIT_TIMEZONE=America/Los_Angeles
SNIPEIT_LOCALE=es-ES
SERVER_URL=https://192.168.99.100:32775
+4 -1
View File
@@ -1,3 +1,6 @@
#!/bin/bash
docker run -v
#docker run -v docker start mysql
# docker run --name snipe-mysql -e MYSQL_ROOT_PASSWORD=fartwingus -e MYSQL_DATABASE=snipeit -e MYSQL_USER=snipeit -e MYSQL_PASSWORD=whateverdood -d mysql
docker run -d snipe-mysql
docker run -d -v ~/Documents/snipeyhead/snipe-it/:/var/www/html -p $(boot2docker ip)::80 --link snipe-mysql:mysql --name=snipeit snipeit
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,350 @@
<?php //[STAMP] 75b677c3515760483cf24695fc5b6099
namespace _generated;
// This class was automatically generated by build task
// You should not change it manually as it will be overwritten on next build
// @codingStandardsIgnoreFile
use Codeception\Module\Filesystem;
use Helper\Functional;
trait FunctionalTesterActions
{
/**
* @return \Codeception\Scenario
*/
abstract protected function getScenario();
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Enters a directory In local filesystem.
* Project root directory is used by default
*
* @param $path
* @see \Codeception\Module\Filesystem::amInPath()
*/
public function amInPath($path) {
return $this->getScenario()->runStep(new \Codeception\Step\Condition('amInPath', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Opens a file and stores it's content.
*
* Usage:
*
* ``` php
* <?php
* $I->openFile('composer.json');
* $I->seeInThisFile('codeception/codeception');
* ?>
* ```
*
* @param $filename
* @see \Codeception\Module\Filesystem::openFile()
*/
public function openFile($filename) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('openFile', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Deletes a file
*
* ``` php
* <?php
* $I->deleteFile('composer.lock');
* ?>
* ```
*
* @param $filename
* @see \Codeception\Module\Filesystem::deleteFile()
*/
public function deleteFile($filename) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('deleteFile', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Deletes directory with all subdirectories
*
* ``` php
* <?php
* $I->deleteDir('vendor');
* ?>
* ```
*
* @param $dirname
* @see \Codeception\Module\Filesystem::deleteDir()
*/
public function deleteDir($dirname) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('deleteDir', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Copies directory with all contents
*
* ``` php
* <?php
* $I->copyDir('vendor','old_vendor');
* ?>
* ```
*
* @param $src
* @param $dst
* @see \Codeception\Module\Filesystem::copyDir()
*/
public function copyDir($src, $dst) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('copyDir', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks If opened file has `text` in it.
*
* Usage:
*
* ``` php
* <?php
* $I->openFile('composer.json');
* $I->seeInThisFile('codeception/codeception');
* ?>
* ```
*
* @param $text
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::seeInThisFile()
*/
public function canSeeInThisFile($text) {
return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInThisFile', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks If opened file has `text` in it.
*
* Usage:
*
* ``` php
* <?php
* $I->openFile('composer.json');
* $I->seeInThisFile('codeception/codeception');
* ?>
* ```
*
* @param $text
* @see \Codeception\Module\Filesystem::seeInThisFile()
*/
public function seeInThisFile($text) {
return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInThisFile', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks the strict matching of file contents.
* Unlike `seeInThisFile` will fail if file has something more than expected lines.
* Better to use with HEREDOC strings.
* Matching is done after removing "\r" chars from file content.
*
* ``` php
* <?php
* $I->openFile('process.pid');
* $I->seeFileContentsEqual('3192');
* ?>
* ```
*
* @param $text
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::seeFileContentsEqual()
*/
public function canSeeFileContentsEqual($text) {
return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeFileContentsEqual', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks the strict matching of file contents.
* Unlike `seeInThisFile` will fail if file has something more than expected lines.
* Better to use with HEREDOC strings.
* Matching is done after removing "\r" chars from file content.
*
* ``` php
* <?php
* $I->openFile('process.pid');
* $I->seeFileContentsEqual('3192');
* ?>
* ```
*
* @param $text
* @see \Codeception\Module\Filesystem::seeFileContentsEqual()
*/
public function seeFileContentsEqual($text) {
return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeFileContentsEqual', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks If opened file doesn't contain `text` in it
*
* ``` php
* <?php
* $I->openFile('composer.json');
* $I->dontSeeInThisFile('codeception/codeception');
* ?>
* ```
*
* @param $text
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::dontSeeInThisFile()
*/
public function cantSeeInThisFile($text) {
return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInThisFile', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks If opened file doesn't contain `text` in it
*
* ``` php
* <?php
* $I->openFile('composer.json');
* $I->dontSeeInThisFile('codeception/codeception');
* ?>
* ```
*
* @param $text
* @see \Codeception\Module\Filesystem::dontSeeInThisFile()
*/
public function dontSeeInThisFile($text) {
return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInThisFile', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Deletes a file
* @see \Codeception\Module\Filesystem::deleteThisFile()
*/
public function deleteThisFile() {
return $this->getScenario()->runStep(new \Codeception\Step\Action('deleteThisFile', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks if file exists in path.
* Opens a file when it's exists
*
* ``` php
* <?php
* $I->seeFileFound('UserModel.php','app/models');
* ?>
* ```
*
* @param $filename
* @param string $path
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::seeFileFound()
*/
public function canSeeFileFound($filename, $path = null) {
return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeFileFound', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks if file exists in path.
* Opens a file when it's exists
*
* ``` php
* <?php
* $I->seeFileFound('UserModel.php','app/models');
* ?>
* ```
*
* @param $filename
* @param string $path
* @see \Codeception\Module\Filesystem::seeFileFound()
*/
public function seeFileFound($filename, $path = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeFileFound', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks if file does not exist in path
*
* @param $filename
* @param string $path
* Conditional Assertion: Test won't be stopped on fail
* @see \Codeception\Module\Filesystem::dontSeeFileFound()
*/
public function cantSeeFileFound($filename, $path = null) {
return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeFileFound', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks if file does not exist in path
*
* @param $filename
* @param string $path
* @see \Codeception\Module\Filesystem::dontSeeFileFound()
*/
public function dontSeeFileFound($filename, $path = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeFileFound', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Erases directory contents
*
* ``` php
* <?php
* $I->cleanDir('logs');
* ?>
* ```
*
* @param $dirname
* @see \Codeception\Module\Filesystem::cleanDir()
*/
public function cleanDir($dirname) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('cleanDir', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Saves contents to file
*
* @param $filename
* @param $contents
* @see \Codeception\Module\Filesystem::writeToFile()
*/
public function writeToFile($filename, $contents) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('writeToFile', func_get_args()));
}
}
@@ -0,0 +1,348 @@
<?php //[STAMP] ea07f1c9c2d6acf94a3a797127238b2d
namespace _generated;
// This class was automatically generated by build task
// You should not change it manually as it will be overwritten on next build
// @codingStandardsIgnoreFile
use Codeception\Module\Asserts;
use Helper\Unit;
trait UnitTesterActions
{
/**
* @return \Codeception\Scenario
*/
abstract protected function getScenario();
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that two variables are equal.
*
* @param $expected
* @param $actual
* @param string $message
*
* @return mixed
* @see \Codeception\Module\Asserts::assertEquals()
*/
public function assertEquals($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEquals', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that two variables are not equal
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNotEquals()
*/
public function assertNotEquals($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotEquals', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that two variables are same
*
* @param $expected
* @param $actual
* @param string $message
*
* @return mixed
* @see \Codeception\Module\Asserts::assertSame()
*/
public function assertSame($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertSame', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that two variables are not same
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNotSame()
*/
public function assertNotSame($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotSame', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that actual is greater than expected
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertGreaterThan()
*/
public function assertGreaterThan($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThan', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @deprecated
* @see \Codeception\Module\Asserts::assertGreaterThen()
*/
public function assertGreaterThen($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThen', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that actual is greater or equal than expected
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertGreaterThanOrEqual()
*/
public function assertGreaterThanOrEqual($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThanOrEqual', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @deprecated
* @see \Codeception\Module\Asserts::assertGreaterThenOrEqual()
*/
public function assertGreaterThenOrEqual($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThenOrEqual', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that actual is less than expected
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertLessThan()
*/
public function assertLessThan($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessThan', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that actual is less or equal than expected
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertLessThanOrEqual()
*/
public function assertLessThanOrEqual($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessThanOrEqual', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that haystack contains needle
*
* @param $needle
* @param $haystack
* @param string $message
* @see \Codeception\Module\Asserts::assertContains()
*/
public function assertContains($needle, $haystack, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertContains', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that haystack doesn't contain needle.
*
* @param $needle
* @param $haystack
* @param string $message
* @see \Codeception\Module\Asserts::assertNotContains()
*/
public function assertNotContains($needle, $haystack, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotContains', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that string match with pattern
*
* @param string $pattern
* @param string $string
* @param string $message
* @see \Codeception\Module\Asserts::assertRegExp()
*/
public function assertRegExp($pattern, $string, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertRegExp', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that string not match with pattern
*
* @param string $pattern
* @param string $string
* @param string $message
* @see \Codeception\Module\Asserts::assertNotRegExp()
*/
public function assertNotRegExp($pattern, $string, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotRegExp', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that variable is empty.
*
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertEmpty()
*/
public function assertEmpty($actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEmpty', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that variable is not empty.
*
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNotEmpty()
*/
public function assertNotEmpty($actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotEmpty', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that variable is NULL
*
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNull()
*/
public function assertNull($actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNull', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that variable is not NULL
*
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNotNull()
*/
public function assertNotNull($actual, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotNull', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that condition is positive.
*
* @param $condition
* @param string $message
* @see \Codeception\Module\Asserts::assertTrue()
*/
public function assertTrue($condition, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertTrue', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that condition is negative.
*
* @param $condition
* @param string $message
* @see \Codeception\Module\Asserts::assertFalse()
*/
public function assertFalse($condition, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFalse', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks if file exists
*
* @param string $filename
* @param string $message
* @see \Codeception\Module\Asserts::assertFileExists()
*/
public function assertFileExists($filename, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFileExists', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks if file doesn't exist
*
* @param string $filename
* @param string $message
* @see \Codeception\Module\Asserts::assertFileNotExists()
*/
public function assertFileNotExists($filename, $message = null) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFileNotExists', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Fails the test with message.
*
* @param $message
* @see \Codeception\Module\Asserts::fail()
*/
public function fail($message) {
return $this->getScenario()->runStep(new \Codeception\Step\Action('fail', func_get_args()));
}
}