In listing page of users in the column of action want add a change_password link and its process of working - laravel

I am using laravel-backpack 4.0. want to add a password change link with a page and all the functionality with validation and all, to a listing of users like edit, in the Action column.

It seems a bit odd to want another page where you can update only the password when the package's built in user crud lets you update that, and all the other user fields. That said, assuming you have your reasons (and that I've understood the usage correctly), one approach would be to use the users addon package suggested but then make a second CRUD controller for the user model that only supports the "update" operation and only allows editing the password.
NOTE
This is untested so there might be some minor issues to iron out, but the approach is sound.
Install and configure the users addon package. Then, create a second controller for users but edit such that only the "update" action is allowed and only the password and password confirmation fields are editable. We'll make the name and email read only so you can see who its for but cant edit those fields. You can make those fields hidden if you want, or remove them, but if you remove them, note that you'll need to create a custom request class and update the rules to not require those fields on submission.
<?php
namespace App\Http\Controllers;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Http\Requests\CrudRequest;
use EduardoArandaH\UserManager\app\Http\Requests\UserStoreCrudRequest as StoreRequest;
use EduardoArandaH\UserManager\app\Http\Requests\UserUpdateCrudRequest as UpdateRequest;
class UserPasswordCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation { update as traitUpdate; }
public function setup()
{
$this->crud->setModel(config('backpack.permissionmanager.models.user'));
$this->crud->setEntityNameStrings('User Password', 'User Passwords');
$this->crud->setRoute(backpack_url('userPasswords'));
$this->crud->denyAccess('create');
$this->crud->denyAccess('list');
$this->crud->denyAccess('delete');
$this->crud->denyAccess('reorder');
$this->crud->denyAccess('revisions');
}
public function setupUpdateOperation()
{
$this->addUserFields();
$this->crud->setValidation(UpdateRequest::class);
}
/**
* Update the specified resource in the database.
*
* #return \Illuminate\Http\RedirectResponse
*/
public function update()
{
$this->crud->setRequest($this->crud->validateRequest());
$this->crud->setRequest($this->handlePasswordInput($this->crud->getRequest()));
$this->crud->unsetValidation(); // validation has already been run
return $this->traitUpdate();
}
/**
* Handle password input fields.
*/
protected function handlePasswordInput($request)
{
// Remove fields not present on the user.
$request->request->remove('password_confirmation');
$request->request->remove('roles_show');
$request->request->remove('permissions_show');
// Encrypt password if specified.
if ($request->input('password')) {
$request->request->set('password', Hash::make($request->input('password')));
} else {
$request->request->remove('password');
}
return $request;
}
protected function addUserFields()
{
$this->crud->addFields([
[
'name' => 'name',
'label' => trans('backpack::permissionmanager.name'),
'type' => 'text',
'attributes' => ['readonly' => 'readonly'],
],
[
'name' => 'email',
'label' => trans('backpack::permissionmanager.email'),
'type' => 'email',
'attributes' => ['readonly' => 'readonly'],
],
[
'name' => 'password',
'label' => trans('backpack::permissionmanager.password'),
'type' => 'password',
],
[
'name' => 'password_confirmation',
'label' => trans('backpack::permissionmanager.password_confirmation'),
'type' => 'password',
],
]);
}
}
Load the route for the new controller:
<?php
Route::group([
'namespace' => 'App\Http\Controllers',
'prefix' => config('backpack.base.route_prefix', 'admin'),
'middleware' => ['web', backpack_middleware()],
], function () {
Route::crud('userPasswords', 'UserPasswordCrudController');
});
Create a custom button at resources/views/vendor/backpack/crud/buttons/update_password.blade.php with this content:
#if ($crud->hasAccess('update'))
<!-- Single edit button -->
<i class="la la-edit"></i>Edit Password
#endif
Finally, in your normal user crud controller (or whatever controller you want the button in) add the button to the line stack in your controller's setupListOperation method:
public function setupListOperation()
{
$this->crud->addButtonFromView('line', 'update_password', 'view', 'end');
// ... normal setup code
}

Related

Laravel Email validation rules fail only on live server. Possible causes?

I run a customer order input through a simple form validation.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CreateOrderWebstoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
// Use additional Address valudation rules if Order is not picked up
// dd('debugging halt',request());
$address_rules = [];
if (! request()->is_pickup) {
$address_rules = [
'street' => 'required|min:3|max:100',
'house_number' => 'required|numeric|max:100000',
'house_number_suffix' => 'nullable|max:10',
'postal_code' => 'required|max:10',
'town' => 'required|min:3|max:50',
'country' => 'required|min:2|max:2',
'region' => 'nullable|min:3|max:50',
'owner' => 'nullable|min:3|max:25',
];
}
return array_merge([
'first_name' => 'required|min:3|max:50',
'middle_name' => 'nullable|min:1|max:15',
'last_name' => 'required|min:3|max:50',
'company_name' => 'nullable|min:3|max:50',
'email_address' => 'required|email:rfc,dns|max:50',
'telephone_number' => 'nullable|min:10|max:25',
'description' => 'nullable|min:5|max:250',
], $address_rules);
}
public function messages()
{
return [
];
}
}
The weird thing this has been working without customer having errors for months. But in de last week or so we suddenly got multiple customers complaining that the validation of their email failed (the first 'rule' that triggers the 'email' response from validation.php
The problem is that testing this on a local host we can't reproduce this, only on the live server.
The host is a shared host, dedicated for Laravel apps, currently running Laravel 6.18.15 and PHP 7.4.16. Local is running running Laravel 6.18.10 and PHP 7.4.2 We had some problems before where the host failed to update PHP, but that doesn't seem to be the case here (if even possible)
The problem is that I don't really know how to fix this or even circumvent it. Changing the email validation to
'email' => 'required|regex:/(.+)#(.+)\.(.+)/i'
is giving me an 'IDN Conversion Failed' error.

Backpack Laravel Admin Incorrectly Redirects after Editing Model

I have a CrudController created for a model using the Backpack Laravel Admin Library.
When I update the model it redirects me incorrectly to a 404 page with the message No query results for model [App\Models\Group].
It is redirecting me to the incorrect URL from what I can tell.
admin/group/261/ instead of admin/group/261/edit
The model also does not update.
I have the "Save and Edit" option set on the green save button. If I try to change this I get the same error, but it doesn't update.
I'm able to save every other model correctly.
The update method in the CrudController is just the following. I've removed all the extra code.
public function update(){
$response = $this->traitUpdate();
return $response;
}
Figured this out. It was because I was referencing the Primary Key -> 'id' in the fields within the Group Crud Controller.
$this->crud->addField([
'name' => 'id',
'type' => 'text',
'attributes' => ['disabled' => 'disabled'],
]);
u can use id, u need delete attribute 'disabled' like this:
[
'name' => 'id',
'label' => 'ID',
'attributes' => [
'readonly' => 'readonly',
],
],

Laravel avoid duplicate entry from model

I'm building a Laravel API. I have a models called Reservations. I want to avoid that a user creates two reservations for the same product and time period.
I have the following:
$reservation = Reservation::firstOrCreate([
'listing_id' => $request->listing_id,
'user_id_from' => $request->user_id_from,
'start_date' => $request->start_date,
'end_date' => $request->end_date,
]);
Edit after comments:
I'm also using validation
$validator = Validator::make($request->all(), [
'listing_id' => 'required|exists:listings,id',
'user_id_from' => 'required|exists:users,id',
'start_date' => 'required|date_format:"Y-m-d"|after:today',
'end_date' => 'required|date_format:"Y-m-d"|after:start_date'
]);
if ($validator->fails()) {
return response()->json(['error' => 'Validation failed'], 403);
}
Validation is working properly.
End of Edit
In my model I have casted the start_date and end_date as dates.
class Reservation extends Model
{
protected $fillable = ['listing_id', 'start_date', 'end_date'];
protected $dates = [
'start_date',
'end_date'
];
....
....
Documentation says:
The firstOrCreate method will attempt to locate a database record
using the given column / value pairs
However I notice that I'm still able to insert entries with the same attributes.
Any idea what I'm doing wrong or suggestions to fix it?
Probably there's a better way than this, but you can create an static method on Reservation to do this, like:
public static function createWithRules($data) {
$exists = $this->where('product_id', $data['product_id'])->whereBetween(*date logic that i don't remember right now*)->first();
if(!$exists) {
* insert logic *
} else {
* product with date exists *
}
}
So you can call Reservation::createWithRules($data)
You can achieve this using Laravel's built in ValidateRequest class. The most simple use-case for this validation, is to call it directly in your store() method like this:
public function store(){
$this->validate($request, [
'listing_id' => 'required|unique,
'start_date' => 'required|unique,
//... and so on
], $this->messages);
$reservation = Reservation::firstOrCreate([
'listing_id' => $request->listing_id,
'user_id_from' => $request->user_id_from,
'start_date' => $request->start_date,
'end_date' => $request->end_date,
]);
}
With this, you're validating users $request with by saying that specified columns are required and that they need to be unique, in order for validation to pass.
In your controller, you can also create messages function to display error messages, if the condition isn't met.
private $messages = [
'listing_id.required' => 'Listing_id is required',
'title.unique' => 'Listing_id already exists',
//... and so on
];
You can also achieve this by creating a new custom validation class:
php artisan make:request StoreReservation
The generated class will be placed in the app/Http/Requests directory. Now, you can add a few validation rules to the rules method:
public function rules()
{
return [
'listing_id' => 'required|unique,
'start_date' => 'required|unique,
//... and so on
];
}
All you need to do now is type-hint the request on your controller method. The incoming form request is validated before the controller method is called, meaning you do not need to clutter your controller with any validation logic:
public function store(StoreReservation $request)
{
// The incoming request is valid...
// Retrieve the validated input data...
$validated = $request->validated();
}
If you have any additional question about this, feel free to ask. Source: Laravel official documentation.

Add custom values in drop down in laravel backpack

I am using laravel back and and I have two tables called bundles and study. I added a drop down fields in the form from bundleCrudController. But I just want to add only those values in the drop down list which studies are created by the logged in user not all the data from studies table.
Here is my code to add data in drop down list -
$this->crud->addField([
'name' => 'studies',
'label' => 'Studies',
'type' => 'select2_from_array',
'options' => $this->Study->getUnallocatedStudies($entryId),
'allows_null' => false,
'hint' => 'Search for the studies you would like to add to this bundle',
'tab' => 'Info',
'allows_multiple' => true
]);
$this->crud->addColumn([
'label' => 'Studies',
'type' => "select_multiple",
'name' => 'bundle_id',
'entity' => 'studies',
'attribute' => 'name',
'model' => "App\Models\Study",
]);
So pls help me to resolve the problem to add only those records in the dropdownlist created by the logged in user not all records.. Thanx
I think the best way would be to create an additional model, UserStudy, that:
extends Study;
has a global scope for filtering for what the current user can see;
It should look something like this:
<?php
namespace App\Models;
use App\Models\Study;
use Auth;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class UserStudy extends Study
{
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
// filter out the studies that don't belong to this user
if (Auth::check()) {
$user = Auth::user();
static::addGlobalScope('user_id', function (Builder $builder) use ($user) {
$builder->where('user_id', $user->id);
});
}
}
}
You'll then be able to use this UserStudy model in your field definition, instead of Study. Just replace App\Models\Study with App\Models\UserStudy.
Hope it helps. Cheers!

Custom Validation Attributes for Array Type Form Fields using proengsoft/laravel-jsvalidation in Laravel 5.2

I am creating a CRUD using dimsav translatable and proengsoft/laravel-jsvalidation packages for Laravel.
The form field names have to follow an array structure like this...
<div class="form-group">
{!! Form::label("es[title]", trans("messages.title"), ["class" => "control-label"]) !!}
{!! Form::text("es[title]", getFormInput($entry, "title", $locale), ["class" => "form-control", "id" => "es[title]"]) !!}
</div>
To be able to use mass asignment easily on the controller.
The create form is being validated with a CreateRequest as follows...
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'es.title' => 'required|max:255',
];
}
}
I don't know how to change the attribute placeholders with more friendly texts at resources/lang/validation.php file. I have tried the following options...
'attributes' => [
'title' => 'título',
//'es.title' => 'título',
//'es[title]' => 'título',
],
...but any of them is working. The form is being validated ok naming the field 'es.title' but the error message showed is not replacing the field name correctly even if I name the attributes array key also 'es.title'. Any ideas?
Inside App/Http/Requests/YourRequest
public function messages()
{
return [
'es.title.required' => 'You forgot título!',
];
}
You can set different messages for different validation rules(required,max etc)
For setting up custom name for an attribute
public function attributes()
{
return [
'es.title' => 'título'
];
}
EDITED
For setting up attribute name globally go to lang/en/validation and you'll see an attribute array. Change it according to you requirement.
'attributes' => [
'es' => [
'title' => 'título'
]
],

Resources