Merge branch 'develop' into vip_tag

This commit is contained in:
snipe 2023-02-01 16:03:23 -08:00 committed by GitHub
commit d9cdb92014
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 373 additions and 297 deletions

View file

@ -303,17 +303,18 @@ class LdapSync extends Command
$user->activated = 0;
} */
$enabled_accounts = [
'512', // 0x200 NORMAL_ACCOUNT
'544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD
'66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD
'66080', // 0x10220 NORMAL_ACCOUNT, PASSWD_NOTREQD, DONT_EXPIRE_PASSWORD
'262656', // 0x40200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED
'262688', // 0x40220 NORMAL_ACCOUNT, PASSWD_NOTREQD, SMARTCARD_REQUIRED
'328192', // 0x50200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'328224', // 0x50220 NORMAL_ACCOUNT, PASSWD_NOT_REQD, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'4194816',// 0x400200 NORMAL_ACCOUNT, DONT_REQ_PREAUTH
'512', // 0x200 NORMAL_ACCOUNT
'544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD
'66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD
'66080', // 0x10220 NORMAL_ACCOUNT, PASSWD_NOTREQD, DONT_EXPIRE_PASSWORD
'262656', // 0x40200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED
'262688', // 0x40220 NORMAL_ACCOUNT, PASSWD_NOTREQD, SMARTCARD_REQUIRED
'328192', // 0x50200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'328224', // 0x50220 NORMAL_ACCOUNT, PASSWD_NOT_REQD, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
'4194816',// 0x400200 NORMAL_ACCOUNT, DONT_REQ_PREAUTH
'4260352', // 0x410200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, DONT_REQ_PREAUTH
'1049088', // 0x100200 NORMAL_ACCOUNT, NOT_DELEGATED
'1114624', // 0x110200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, NOT_DELEGATED,
];
$user->activated = (in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts)) ? 1 : 0;

View file

@ -63,6 +63,7 @@ class AccessoriesController extends Controller
public function store(ImageUploadRequest $request)
{
$this->authorize(Accessory::class);
// create a new model instance
$accessory = new Accessory();
@ -82,7 +83,6 @@ class AccessoriesController extends Controller
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
// Was the accessory created?
@ -127,45 +127,47 @@ class AccessoriesController extends Controller
*/
public function update(ImageUploadRequest $request, $accessoryId = null)
{
if (is_null($accessory = Accessory::find($accessoryId))) {
if ($accessory = Accessory::withCount('users as users_count')->find($accessoryId)) {
$this->authorize($accessory);
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$accessory->users_count"
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
// Update the accessory data
$accessory->name = request('name');
$accessory->location_id = request('location_id');
$accessory->min_amt = request('min_amt');
$accessory->category_id = request('category_id');
$accessory->company_id = Company::getIdForCurrentUser(request('company_id'));
$accessory->manufacturer_id = request('manufacturer_id');
$accessory->order_number = request('order_number');
$accessory->model_number = request('model_number');
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
// Was the accessory updated?
if ($accessory->save()) {
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success'));
}
} else {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
$min = $accessory->numCheckedOut();
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$min"
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$this->authorize($accessory);
// Update the accessory data
$accessory->name = request('name');
$accessory->location_id = request('location_id');
$accessory->min_amt = request('min_amt');
$accessory->category_id = request('category_id');
$accessory->company_id = Company::getIdForCurrentUser(request('company_id'));
$accessory->manufacturer_id = request('manufacturer_id');
$accessory->order_number = request('order_number');
$accessory->model_number = request('model_number');
$accessory->purchase_date = request('purchase_date');
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
$accessory->qty = request('qty');
$accessory->supplier_id = request('supplier_id');
$accessory->notes = request('notes');
$accessory = $request->handleImages($accessory);
// Was the accessory updated?
if ($accessory->save()) {
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($accessory->getErrors());
}
@ -217,7 +219,7 @@ class AccessoriesController extends Controller
*/
public function show($accessoryID = null)
{
$accessory = Accessory::find($accessoryID);
$accessory = Accessory::withCount('users as users_count')->find($accessoryID);
$this->authorize('view', $accessory);
if (isset($accessory->id)) {
return view('accessories/view', compact('accessory'));

View file

@ -222,8 +222,8 @@ class AcceptanceController extends Controller
'item_model' => $display_model,
'item_serial' => $item->serial,
'eula' => $item->getEula(),
'check_out_date' => Carbon::parse($acceptance->created_at)->format($branding_settings->date_display_format),
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format($branding_settings->date_display_format),
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
'assigned_to' => $assigned_to,
'company_name' => $branding_settings->site_name,
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
@ -273,7 +273,7 @@ class AcceptanceController extends Controller
'item_tag' => $item->asset_tag,
'item_model' => $display_model,
'item_serial' => $item->serial,
'declined_date' => Carbon::parse($acceptance->accepted_at)->format($branding_settings->date_display_format),
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
'assigned_to' => $assigned_to,
'company_name' => $branding_settings->site_name,
'date_settings' => $branding_settings->date_display_format,

View file

@ -41,10 +41,13 @@ class AccessoriesController extends Controller
'min_amt',
'company_id',
'notes',
'users_count',
'qty',
];
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'users', 'location', 'supplier');
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'users', 'location', 'supplier')
->withCount('users as users_count');
if ($request->filled('search')) {
$accessories = $accessories->TextSearch($request->input('search'));

View file

@ -33,7 +33,7 @@ class CustomFieldsetsController extends Controller
*/
public function index()
{
$this->authorize('index', CustomFieldset::class);
$this->authorize('index', CustomField::class);
$fieldsets = CustomFieldset::withCount('fields as fields_count', 'models as models_count')->get();
return (new CustomFieldsetsTransformer)->transformCustomFieldsets($fieldsets, $fieldsets->count());
@ -49,7 +49,7 @@ class CustomFieldsetsController extends Controller
*/
public function show($id)
{
$this->authorize('view', CustomFieldset::class);
$this->authorize('view', CustomField::class);
if ($fieldset = CustomFieldset::find($id)) {
return (new CustomFieldsetsTransformer)->transformCustomFieldset($fieldset);
}
@ -68,7 +68,7 @@ class CustomFieldsetsController extends Controller
*/
public function update(Request $request, $id)
{
$this->authorize('update', CustomFieldset::class);
$this->authorize('update', CustomField::class);
$fieldset = CustomFieldset::findOrFail($id);
$fieldset->fill($request->all());
@ -89,7 +89,7 @@ class CustomFieldsetsController extends Controller
*/
public function store(Request $request)
{
$this->authorize('create', CustomFieldset::class);
$this->authorize('create', CustomField::class);
$fieldset = new CustomFieldset;
$fieldset->fill($request->all());
@ -109,7 +109,7 @@ class CustomFieldsetsController extends Controller
*/
public function destroy($id)
{
$this->authorize('delete', CustomFieldset::class);
$this->authorize('delete', CustomField::class);
$fieldset = CustomFieldset::findOrFail($id);
$modelsCount = $fieldset->models->count();
@ -136,7 +136,7 @@ class CustomFieldsetsController extends Controller
*/
public function fields($id)
{
$this->authorize('view', CustomFieldset::class);
$this->authorize('view', CustomField::class);
$set = CustomFieldset::findOrFail($id);
$fields = $set->fields;
@ -153,7 +153,7 @@ class CustomFieldsetsController extends Controller
*/
public function fieldsWithDefaultValues($fieldsetId, $modelId)
{
$this->authorize('view', CustomFieldset::class);
$this->authorize('view', CustomField::class);
$set = CustomFieldset::findOrFail($fieldsetId);

View file

@ -544,8 +544,9 @@ class UsersController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.inventorynotification.error')));
}
return response()->Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success'));
$user->notify((new CurrentInventory($user)));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success')));
}
/**

View file

@ -75,9 +75,9 @@ class CustomFieldsetsController extends Controller
*/
public function create()
{
$this->authorize('create', CustomFieldset::class);
$this->authorize('create', CustomField::class);
return view('custom_fields.fieldsets.edit');
return view('custom_fields.fieldsets.edit')->with('item', new CustomFieldset());
}
/**
@ -91,7 +91,7 @@ class CustomFieldsetsController extends Controller
*/
public function store(Request $request)
{
$this->authorize('create', CustomFieldset::class);
$this->authorize('create', CustomField::class);
$cfset = new CustomFieldset([
'name' => e($request->get('name')),
@ -110,31 +110,52 @@ class CustomFieldsetsController extends Controller
}
/**
* What the actual fuck, Brady?
* Presents edit form for fieldset
*
* @todo Uhh, build this?
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $id
* @since [v1.8]
* @return Fuckall
* @since [v6.0.14]
* @return Redirect
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit($id)
{
//
$this->authorize('create', CustomField::class);
if ($fieldset = CustomFieldset::find($id)) {
return view('custom_fields.fieldsets.edit')->with('item', $fieldset);
}
return redirect()->route('fields.index')->with('error', trans('admin/custom_fields/general.fieldset_does_not_exist', ['id' => $id]));
}
/**
* GET IN THE SEA BRADY.
* Saves updated fieldset data
*
* @todo Uhh, build this too?
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $id
* @since [v1.8]
* @return Fuckall
* @since [v6.0.14]
* @return Redirect
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update($id)
public function update(Request $request, $id)
{
//
$this->authorize('create', CustomField::class);
if ($fieldset = CustomFieldset::find($id)) {
$fieldset->name = $request->input('name');
if ($fieldset->save()) {
return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/general.fieldset_updated'));
}
return redirect()->back()->withInput()->withErrors($fieldset->getErrors());
}
return redirect()->route('fields.index')->with('error', trans('admin/custom_fields/general.fieldset_does_not_exist', ['id' => $id]));
}
/**
@ -148,7 +169,7 @@ class CustomFieldsetsController extends Controller
*/
public function destroy($id)
{
$fieldset = CustomFieldset::find($id);
$fieldset = CustomField::find($id);
$this->authorize('delete', $fieldset);
@ -175,7 +196,7 @@ class CustomFieldsetsController extends Controller
*/
public function associate(Request $request, $id)
{
$set = CustomFieldset::find($id);
$set = CustomField::find($id);
$this->authorize('update', $set);
@ -202,7 +223,7 @@ class CustomFieldsetsController extends Controller
*/
public function makeFieldRequired($fieldset_id, $field_id)
{
$this->authorize('update', CustomFieldset::class);
$this->authorize('update', CustomField::class);
$field = CustomField::findOrFail($field_id);
$fieldset = CustomFieldset::findOrFail($fieldset_id);
$fields[$field->id] = ['required' => 1];
@ -220,7 +241,7 @@ class CustomFieldsetsController extends Controller
*/
public function makeFieldOptional($fieldset_id, $field_id)
{
$this->authorize('update', CustomFieldset::class);
$this->authorize('update', CustomField::class);
$field = CustomField::findOrFail($field_id);
$fieldset = CustomFieldset::findOrFail($fieldset_id);
$fields[$field->id] = ['required' => 0];

View file

@ -38,7 +38,8 @@ class AccessoriesTransformer
'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost),
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
'remaining_qty' => $accessory->numRemaining(),
'remaining_qty' => (int) $accessory->numRemaining(),
'users_count' => $accessory->users_count,
'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'),

View file

@ -327,20 +327,6 @@ class Accessory extends SnipeModel
return null;
}
/**
* Check how many items within an accessory are checked out
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.0]
* @return int
*/
public function numCheckedOut()
{
$checkedout = 0;
$checkedout = $this->users->count();
return $checkedout;
}
/**
* Check how many items of an accessory remain
@ -351,11 +337,11 @@ class Accessory extends SnipeModel
*/
public function numRemaining()
{
$checkedout = $this->users->count();
$checkedout = $this->users_count;
$total = $this->qty;
$remaining = $total - $checkedout;
return $remaining;
return (int) $remaining;
}
/**

View file

@ -12,92 +12,7 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
{
public function getUserConfig()
{
$config = parent::getUserConfig();
// Much of this is copied verbatim from the library, then adjusted for our needs
$config['class'] = SCIMUser::class;
unset($config['mapping']['example:name:space']);
$config['map_unmapped'] = false; // anything we don't explicitly map will _not_ show up.
$core_namespace = 'urn:ietf:params:scim:schemas:core:2.0:User';
$core = $core_namespace.':';
$mappings =& $config['mapping'][$core_namespace]; //grab this entire key, we don't want to be repeating ourselves
//username - *REQUIRED*
$config['validations'][$core.'userName'] = 'required';
$mappings['userName'] = AttributeMapping::eloquent('username');
//human name - *FIRST NAME REQUIRED*
$config['validations'][$core.'name.givenName'] = 'required';
$config['validations'][$core.'name.familyName'] = 'string'; //not required
$mappings['name']['familyName'] = AttributeMapping::eloquent("last_name");
$mappings['name']['givenName'] = AttributeMapping::eloquent("first_name");
$mappings['name']['formatted'] = (new AttributeMapping())->ignoreWrite()->setRead(
function (&$object) {
return $object->getFullNameAttribute();
}
);
// externalId support
$config['validations'][$core.'externalId'] = 'string|nullable'; // not required, but supported mostly just for Okta
// note that the mapping is *not* namespaced like the other $mappings
$config['mapping']['externalId'] = AttributeMapping::eloquent('scim_externalid');
$config['validations'][$core.'emails'] = 'nullable|array'; // emails are not required in Snipe-IT...
$config['validations'][$core.'emails.*.value'] = 'email'; // ...(had to remove the recommended 'required' here)
$mappings['emails'] = [[
"value" => AttributeMapping::eloquent("email"),
"display" => null,
"type" => AttributeMapping::constant("work")->ignoreWrite(),
"primary" => AttributeMapping::constant(true)->ignoreWrite()
]];
//active
$config['validations'][$core.'active'] = 'boolean';
$mappings['active'] = AttributeMapping::eloquent('activated');
//phone
$config['validations'][$core.'phoneNumbers'] = 'nullable|array';
$config['validations'][$core.'phoneNumbers.*.value'] = 'string'; // another one where want to say 'we don't _need_ a phone number, but if you have one it better have a value.
$mappings['phoneNumbers'] = [[
"value" => AttributeMapping::eloquent("phone"),
"display" => null,
"type" => AttributeMapping::constant("work")->ignoreWrite(),
"primary" => AttributeMapping::constant(true)->ignoreWrite()
]];
//address
$config['validations'][$core.'addresses'] = 'nullable|array';
$config['validations'][$core.'addresses.*.streetAddress'] = 'string';
$config['validations'][$core.'addresses.*.locality'] = 'string';
$config['validations'][$core.'addresses.*.region'] = 'nullable|string';
$config['validations'][$core.'addresses.*.postalCode'] = 'nullable|string';
$config['validations'][$core.'addresses.*.country'] = 'string';
$mappings['addresses'] = [[
'type' => AttributeMapping::constant("work")->ignoreWrite(),
'formatted' => AttributeMapping::constant("n/a")->ignoreWrite(), // TODO - is this right? This doesn't look right.
'streetAddress' => AttributeMapping::eloquent("address"),
'locality' => AttributeMapping::eloquent("city"),
'region' => AttributeMapping::eloquent("state"),
'postalCode' => AttributeMapping::eloquent("zip"),
'country' => AttributeMapping::eloquent("country"),
'primary' => AttributeMapping::constant(true)->ignoreWrite() //this isn't in the example?
]];
//title
$config['validations'][$core.'title'] = 'string';
$mappings['title'] = AttributeMapping::eloquent('jobtitle');
//Preferred Language
$config['validations'][$core.'preferredLanguage'] = 'string';
$mappings['preferredLanguage'] = AttributeMapping::eloquent('locale');
/*
more snipe-it attributes I'd like to check out (to map to 'enterprise' maybe?):
@ -108,66 +23,213 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
- company_id to "organization?"
*/
$enterprise_namespace = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
$ent = $enterprise_namespace.':';
// we remove the 'example' namespace and add the Enterprise one
$config['mapping']['schemas'] = AttributeMapping::constant( [$core_namespace, $enterprise_namespace] )->ignoreWrite();
$user_prefix = 'urn:ietf:params:scim:schemas:core:2.0:User:';
$enterprise_prefix = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:';
$config['validations'][$ent.'employeeNumber'] = 'string';
$config['validations'][$ent.'department'] = 'string';
$config['validations'][$ent.'manager'] = 'nullable';
$config['validations'][$ent.'manager.value'] = 'string';
return [
$config['mapping'][$enterprise_namespace] = [
'employeeNumber' => AttributeMapping::eloquent('employee_num'),
'department' =>(new AttributeMapping())->setAdd( // FIXME parent?
function ($value, &$object) {
$department = Department::where("name", $value)->first();
if ($department) {
$object->department_id = $department->id;
}
}
)->setReplace(
function ($value, &$object) {
$department = Department::where("name", $value)->first();
if ($department) {
$object->department_id = $department->id;
// Set to 'null' to make use of auth.providers.users.model (App\User::class)
'class' => SCIMUser::class,
'validations' => [
$user_prefix . 'userName' => 'required',
$user_prefix . 'name.givenName' => 'required',
$user_prefix . 'name.familyName' => 'nullable|string',
$user_prefix . 'externalId' => 'nullable|string',
$user_prefix . 'emails' => 'nullable|array',
$user_prefix . 'emails.*.value' => 'nullable|email',
$user_prefix . 'active' => 'boolean',
$user_prefix . 'phoneNumbers' => 'nullable|array',
$user_prefix . 'phoneNumbers.*.value' => 'nullable|string',
$user_prefix . 'addresses' => 'nullable|array',
$user_prefix . 'addresses.*.streetAddress' => 'nullable|string',
$user_prefix . 'addresses.*.locality' => 'nullable|string',
$user_prefix . 'addresses.*.region' => 'nullable|string',
$user_prefix . 'addresses.*.postalCode' => 'nullable|string',
$user_prefix . 'addresses.*.country' => 'nullable|string',
$user_prefix . 'title' => 'nullable|string',
$user_prefix . 'preferredLanguage' => 'nullable|string',
// Enterprise validations:
$enterprise_prefix . 'employeeNumber' => 'nullable|string',
$enterprise_prefix . 'department' => 'nullable|string',
$enterprise_prefix . 'manager' => 'nullable',
$enterprise_prefix . 'manager.value' => 'nullable|string'
],
'singular' => 'User',
'schema' => [Schema::SCHEMA_USER],
//eager loading
'withRelations' => [],
'map_unmapped' => false,
// 'unmapped_namespace' => 'urn:ietf:params:scim:schemas:laravel:unmapped',
'description' => 'User Account',
// Map a SCIM attribute to an attribute of the object.
'mapping' => [
'id' => AttributeMapping::eloquent("id")->disableWrite(),
'externalId' => AttributeMapping::eloquent('scim_externalid'), // FIXME - I have a PR that changes a lot of this.
'meta' => [
'created' => AttributeMapping::eloquent("created_at")->disableWrite(),
'lastModified' => AttributeMapping::eloquent("updated_at")->disableWrite(),
'location' => (new AttributeMapping())->setRead(
function ($object) {
return route(
'scim.resource',
[
'resourceType' => 'Users',
'resourceObject' => $object->id
]
);
}
}
)->setRead(
function (&$object) {
return $object->department ? $object->department->name : null;
}
),
'manager' => [
// FIXME - manager writes are disabled. This kinda works but it leaks errors all over the place. Not cool.
// '$ref' => (new AttributeMapping())->ignoreWrite()->ignoreRead(),
// 'displayName' => (new AttributeMapping())->ignoreWrite()->ignoreRead(),
// NOTE: you could probably do a 'plain' Eloquent mapping here, but we don't for future-proofing
'value' => (new AttributeMapping())->setAdd(
function ($value, &$object) {
$manager = User::find($value);
if ($manager) {
$object->manager_id = $manager->id;
)->disableWrite(),
'resourceType' => AttributeMapping::constant("User")
],
'schemas' => AttributeMapping::constant(
[
'urn:ietf:params:scim:schemas:core:2.0:User',
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User'
]
)->ignoreWrite(),
'urn:ietf:params:scim:schemas:core:2.0:User' => [
'userName' => AttributeMapping::eloquent("username"),
'name' => [
'formatted' => (new AttributeMapping())->ignoreWrite()->setRead(
function (&$object) {
return $object->getFullNameAttribute();
}
),
'familyName' => AttributeMapping::eloquent("last_name"),
'givenName' => AttributeMapping::eloquent("first_name"),
'middleName' => null,
'honorificPrefix' => null,
'honorificSuffix' => null
],
'displayName' => null,
'nickName' => null,
'profileUrl' => null,
'title' => AttributeMapping::eloquent('jobtitle'),
'userType' => null,
'preferredLanguage' => AttributeMapping::eloquent('locale'), // Section 5.3.5 of [RFC7231]
'locale' => null, // see RFC5646
'timezone' => null, // see RFC6557
'active' => AttributeMapping::eloquent('activated'),
'password' => AttributeMapping::eloquent('password')->disableRead(),
// Multi-Valued Attributes
'emails' => [[
"value" => AttributeMapping::eloquent("email"),
"display" => null,
"type" => AttributeMapping::constant("work")->ignoreWrite(),
"primary" => AttributeMapping::constant(true)->ignoreWrite()
]],
'phoneNumbers' => [[
"value" => AttributeMapping::eloquent("phone"),
"display" => null,
"type" => AttributeMapping::constant("work")->ignoreWrite(),
"primary" => AttributeMapping::constant(true)->ignoreWrite()
]],
'ims' => [[
"value" => null,
"display" => null,
"type" => null,
"primary" => null
]], // Instant messaging addresses for the User
'photos' => [[
"value" => null,
"display" => null,
"type" => null,
"primary" => null
]],
'addresses' => [[
'type' => AttributeMapping::constant("work")->ignoreWrite(),
'formatted' => AttributeMapping::constant("n/a")->ignoreWrite(), // TODO - is this right? This doesn't look right.
'streetAddress' => AttributeMapping::eloquent("address"),
'locality' => AttributeMapping::eloquent("city"),
'region' => AttributeMapping::eloquent("state"),
'postalCode' => AttributeMapping::eloquent("zip"),
'country' => AttributeMapping::eloquent("country"),
'primary' => AttributeMapping::constant(true)->ignoreWrite() //this isn't in the example?
]],
'groups' => [[
'value' => null,
'$ref' => null,
'display' => null,
'type' => null,
'type' => null
]],
'entitlements' => null,
'roles' => null,
'x509Certificates' => null
],
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User' => [
'employeeNumber' => AttributeMapping::eloquent('employee_num'),
'department' => (new AttributeMapping())->setAdd( // FIXME parent?
function ($value, &$object) {
$department = Department::where("name", $value)->first();
if ($department) {
$object->department_id = $department->id;
}
}
}
)->setReplace(
function ($value, &$object) {
$manager = User::find($value);
if ($manager) {
$object->manager_id = $manager->id;
$department = Department::where("name", $value)->first();
if ($department) {
$object->department_id = $department->id;
}
}
)->setRead(
function (&$object) {
return $object->manager_id;
return $object->department ? $object->department->name : null;
}
),
'manager' => [
// FIXME - manager writes are disabled. This kinda works but it leaks errors all over the place. Not cool.
// '$ref' => (new AttributeMapping())->ignoreWrite()->ignoreRead(),
// 'displayName' => (new AttributeMapping())->ignoreWrite()->ignoreRead(),
// NOTE: you could probably do a 'plain' Eloquent mapping here, but we don't for future-proofing
'value' => (new AttributeMapping())->setAdd(
function ($value, &$object) {
$manager = User::find($value);
if ($manager) {
$object->manager_id = $manager->id;
}
}
)->setReplace(
function ($value, &$object) {
$manager = User::find($value);
if ($manager) {
$object->manager_id = $manager->id;
}
}
)->setRead(
function (&$object) {
return $object->manager_id;
}
),
]
]
]
];
return $config;
}
}

View file

@ -80,19 +80,25 @@ class AccessoryPresenter extends Presenter
], [
'field' => 'qty',
'searchable' => false,
'sortable' => false,
'title' => trans('admin/accessories/general.total'),
], [
'field' => 'min_qty',
'searchable' => false,
'sortable' => true,
'title' => trans('general.min_amt'),
'title' => trans('admin/accessories/general.total'),
], [
'field' => 'remaining_qty',
'searchable' => false,
'sortable' => false,
'visible' => false,
'title' => trans('admin/accessories/general.remaining'),
],[
'field' => 'users_count',
'searchable' => false,
'sortable' => true,
'visible' => true,
'title' => trans('general.checked_out'),
], [
'field' => 'min_qty',
'searchable' => false,
'sortable' => true,
'title' => trans('general.min_amt'),
], [
'field' => 'purchase_date',
'searchable' => true,

8
composer.lock generated
View file

@ -78,12 +78,12 @@
"source": {
"type": "git",
"url": "https://github.com/grokability/laravel-scim-server.git",
"reference": "2c7ecc450eee59234e059ec2e7724b2d8f3a8369"
"reference": "9e8dd2d3958d3c3c05d0a99fe6475361ad9e9419"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/grokability/laravel-scim-server/zipball/2c7ecc450eee59234e059ec2e7724b2d8f3a8369",
"reference": "2c7ecc450eee59234e059ec2e7724b2d8f3a8369",
"url": "https://api.github.com/repos/grokability/laravel-scim-server/zipball/9e8dd2d3958d3c3c05d0a99fe6475361ad9e9419",
"reference": "9e8dd2d3958d3c3c05d0a99fe6475361ad9e9419",
"shasum": ""
},
"require": {
@ -133,7 +133,7 @@
"support": {
"source": "https://github.com/grokability/laravel-scim-server/tree/master"
},
"time": "2022-11-22T20:26:54+00:00"
"time": "2023-01-12T00:32:07+00:00"
},
{
"name": "asm89/stack-cors",

View file

@ -102,6 +102,7 @@ return [
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),

View file

@ -3,6 +3,6 @@
return [
"trace" => env("SCIM_TRACE",false),
// below, if we ever get 'sure' that we can change this default to 'true' we should
"omit_main_schema_in_return" => env('SCIM_STANDARDS_COMPLIANCE', false),
"omit_main_schema_in_return" => env('SCIM_STANDARDS_COMPLIANCE', true),
"publish_routes" => false,
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -12,4 +12,5 @@ return array(
'remaining' => 'Remaining',
'total' => 'Total',
'update' => 'Update Component',
'checkin_limit' => 'Amount checked in must be equal to or less than :assigned_qty'
);

View file

@ -27,6 +27,9 @@ return [
'used_by_models' => 'Used By Models',
'order' => 'Order',
'create_fieldset' => 'New Fieldset',
'update_fieldset' => 'Update Fieldset',
'fieldset_does_not_exist' => 'Fieldset :id does not exist',
'fieldset_updated' => 'Fieldset updated',
'create_fieldset_title' => 'Create a new fieldset',
'create_field' => 'New Custom Field',
'create_field_title' => 'Create a new custom field',

0
resources/views/accessories/edit.blade.php Executable file → Normal file
View file

View file

@ -290,7 +290,7 @@
@if ($accessory->company)
<div class="row">
<div class="col-md-4" style="padding-bottom: 15px;">
{{ trans('general.company')}}
<strong> {{ trans('general.company')}}</strong>
</div>
<div class="col-md-8">
<a href="{{ route('companies.show', $accessory->company->id) }}">{{ $accessory->company->name }} </a>
@ -302,7 +302,7 @@
@if ($accessory->category)
<div class="row">
<div class="col-md-4" style="padding-bottom: 15px;">
{{ trans('general.category')}}
<strong>{{ trans('general.category')}}</strong>
</div>
<div class="col-md-8">
<a href="{{ route('categories.show', $accessory->category->id) }}">{{ $accessory->category->name }} </a>
@ -327,13 +327,22 @@
<div class="row">
<div class="col-md-4" style="padding-bottom: 15px;">
Number remaining
<strong>{{ trans('admin/accessories/general.remaining') }}</strong>
</div>
<div class="col-md-8">
{{ $accessory->numRemaining() }}
</div>
</div>
<div class="row">
<div class="col-md-4" style="padding-bottom: 15px;">
<strong>{{ trans('general.checked_out') }}</strong>
</div>
<div class="col-md-8">
{{ $accessory->users_count }}
</div>
</div>
@can('checkout', \App\Models\Accessory::class)

View file

@ -42,7 +42,7 @@
<input type="text" class="form-control" name="checkin_qty" aria-label="checkin_qty" value="{{ old('assigned_qty', $component_assets->assigned_qty) }}">
</div>
<div class="col-md-9 col-md-offset-2">
<p class="help-block">Must be {{ $component_assets->assigned_qty }} or less.</p>
<p class="help-block">{{ trans('admin/components/general.checkin_limit', ['assigned_qty' => $component_assets->assigned_qty]) }}</p>
{!! $errors->first('checkin_qty', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i>
:message</span>') !!}
</div>

View file

@ -60,7 +60,7 @@
@if ($snipeSettings->slack_endpoint!='')
<i class="fab fa-slack"></i>
A slack message will be sent
{{ trans('general.slack_msg_note') }}
@endif
</div>
</div>

View file

@ -1,49 +1,17 @@
@extends('layouts.default')
@extends('layouts/edit-form', [
'createText' => trans('admin/custom_fields/general.create_fieldset') ,
'updateText' => trans('admin/custom_fields/general.update_fieldset'),
'helpText' => trans('admin/custom_fields/general.about_fieldsets_text'),
'helpPosition' => 'right',
'formAction' => (isset($item->id)) ? route('fieldsets.update', ['fieldset' => $item->id]) : route('fieldsets.store'),
])
{{-- Page title --}}
@section('title')
{{ trans('admin/custom_fields/general.create_fieldset') }}
@parent
@stop
@section('header_right')
<a href="{{ URL::previous() }}" class="btn btn-primary pull-right">
{{ trans('general.back') }}</a>
@stop
{{-- Page content --}}
@section('content')
<div class="row">
<div class="col-md-9">
{{ Form::open(['route' => 'fieldsets.store', 'class'=>'form-horizontal']) }}
<!-- Horizontal Form -->
<div class="box box-default">
<div class="box-body">
<!-- Name -->
<div class="form-group {{ $errors->has('name') ? ' has-error' : '' }}">
<label for="name" class="col-md-4 control-label">
{{ trans('admin/custom_fields/general.fieldset_name') }}
</label>
<div class="col-md-6">
<input class="form-control" type="text" name="name" id="name" value="{{ old('name') }}" required>
{!! $errors->first('name', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
</div>
</div> <!-- /.box-body-->
<div class="box-footer text-right">
<button type="submit" class="btn btn-success"><i class="fas fa-check icon-white" aria-hidden="true"></i> {{ trans('general.save') }}</button>
</div>
</div> <!-- /.box.box-default-->
{{ Form::close() }}
</div>
<div class="col-md-3">
<h2>{{ trans('admin/custom_fields/general.about_fieldsets_title') }}</h4>
<p>{{ trans('admin/custom_fields/general.about_fieldsets_text') }}</p>
</div>
</div>
@parent
@stop
@section('inputFields')
@include ('partials.forms.edit.name', ['translated_name' => trans('general.name')])
@stop

View file

@ -69,8 +69,18 @@
@endforeach
</td>
<td>
<nobr>
@can('update', $fieldset)
<a href="{{ route('fieldsets.edit', $fieldset->id) }}" class="btn btn-warning btn-sm">
<i class="fas fa-pencil-alt" aria-hidden="true"></i>
<span class="sr-only">{{ trans('button.edit') }}</span>
</a>
@endcan
@can('delete', $fieldset)
{{ Form::open(['route' => array('fieldsets.destroy', $fieldset->id), 'method' => 'delete']) }}
{{ Form::open(['route' => array('fieldsets.destroy', $fieldset->id), 'method' => 'delete','style' => 'display:inline-block']) }}
@if($fieldset->models->count() > 0)
<button type="submit" class="btn btn-danger btn-sm disabled" disabled><i class="fas fa-trash"></i></button>
@else
@ -78,6 +88,7 @@
@endif
{{ Form::close() }}
@endcan
</nobr>
</td>
</tr>
@endforeach

View file

@ -15,8 +15,8 @@
<link rel="apple-touch-icon" href="{{ ($snipeSettings) && ($snipeSettings->favicon!='') ? Storage::disk('public')->url(e($snipeSettings->logo)) : config('app.url').'/img/logo.png' }}">
<link rel="apple-touch-startup-image" href="{{ ($snipeSettings) && ($snipeSettings->favicon!='') ? Storage::disk('public')->url(e($snipeSettings->logo)) : config('app.url').'/img/logo.png' }}">
<link rel="apple-touch-icon" href="{{ ($snipeSettings) && ($snipeSettings->favicon!='') ? Storage::disk('public')->url(e($snipeSettings->logo)) : config('app.url').'/img/snipe-logo-bug.png' }}">
<link rel="apple-touch-startup-image" href="{{ ($snipeSettings) && ($snipeSettings->favicon!='') ? Storage::disk('public')->url(e($snipeSettings->logo)) : config('app.url').'/img/snipe-logo-bug.png' }}">
<link rel="shortcut icon" type="image/ico" href="{{ ($snipeSettings) && ($snipeSettings->favicon!='') ? Storage::disk('public')->url(e($snipeSettings->favicon)) : config('app.url').'/favicon.ico' }} ">

View file

@ -327,8 +327,8 @@
item_icon = '';
}
// display the username if it's checked out to a user
if (value.username) {
// display the username if it's checked out to a user, but don't do it if the username's there already
if (value.username && !value.name.match('\\(') && !value.name.match('\\)')) {
value.name = value.name + ' (' + value.username + ')';
}