Disable the button after the click, and change it's value - php

I have a Laravel project, where I allow people to subscribe to specific campaigns. There is a button "Subscribe", and once pressed, I write the information in the pivot table.
The relation between User and Campaign is belongsToMany both ways.
The question is, how could I disable such button, so client's couldn't subscribe to the same campaign many times? In my thoughts, after the button click, it would get disabled, and would show "Subscribed".
Current button:
<x-button>
Subscribe
</x-button>
EDIT:
So I had an idea, to check if this specific combination of campaign_id and user_id exists within the pivot table, and get a boolean.
Controller
public static function button(Request $request)
{
$campaignUser = User::find($request->user()->id);
$hasCampaign = $campaignUser->campaigns()->where('id', $request->id)->exists();
return $hasCampaign;
}
I do receive a proper response, either 1 or something else.
Now I am trying to call it from the view (still checking if it would work):
#if(App\Http\Controllers\SubscribeController::button() == 1)
echo "Yes";
#else
echo "No";
#endif
The current issue, is that of course, I need to somehow pass the Request $request into the function, though, not sure if it is even possible.
If it would work like that, I would try to adjust my button code by example:
<input type="hidden" name="status" value="{{ $post->status == 1 ? 0 : 1 }}"/>
#if($post->status == 1)
<input type="submit" value="Subscribed"/>
#else
<input type="submit" value="Subscribe"/>
#endif
So the current question, is if I am even doing it correctly, and if so, how to pass the Request into the function?

Related

PHP MVC User Management

I'm creating my own PHP MVC Framework and want to manage users, for this I have a dynamic url that is created with a form action like the following:
<form action="users/delete/<?=$user->id?>" method="post">
<input type="hidden" name="_method" value="delete-submit" name="delete-submit">
<button type="submit" class="btn bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">Delete</button>
</form>
I don't know if this is the right way to do it, so I'm asking.
This redirects to /users/delete/$id but do I need to handle the form requests like this:
if(!empty($_POST['delete-submit'])) {
$user = $this->model("user");
$user->deleteUser($value);
header("Location:".ROUTE."home/users");
}
or can I just work with the url and ignore the POST request.
I wouldn't count on $_POST['delete-submit'] variable, cause for example if you use tool like Postman, you can create such request manually and delete any user, considering you are just checking if $_POST['delete-submit'] is set or not.
So if you are deleting user, there should be some authorization mechanism.
users/delete route for deleting users -> That's Correct
Then you check via $_SESSION['UserId'], which user is making such request and if he is authorized / has such permission, you delete the user..
Like...
function deleteUser($userId) {
if(user::hasDeletePermission($_SESSION['UserId']) {
'delete the user';
}
}
If you already have such authorization based mechanism and just need additional check, user really submitted / clicked on that button or not, for CSRF attacks for example, then I would create Token (some random string with numbers and characters) and save into user's session, which would be embedded into form as a hidden input element's value.
Like:
<form method="POST" action="users/delete">
<input type="hidden" name="csrfToken" value="token"/>
</form>
function deleteUser($userId) {
if($_POST['csrfToken'] === $_SESSION['csrfToken'] && user::hasDeletePermission($_SESSION['UserId']) {
'delete the user';
}
}

Hidden inputs in Laravel blade.php

Hey so I'm trying to sort entries by a type of pet, the code below is code from my blade.php
<div>
<td>
<form>
#csrf
<input name="cat" type="hidden" value="cat">
<a name="cat" href="{{ url('sorting') }}" value="cat">Cat</a>
</form>
</td>
</div>
In the blade file I'd have multiple links such as cat, dog, rabbit which essentially act as filtering options
I have a sort method in my controller that does the following
public function sorting(Request $request){
if($request->input('cat') === 'cat'){
$pets = Pet::Where('type', 'cat')->get();
return view('index', compact('pets'));
}
}
In my sort method, I'm trying to check if the cat link is clicked and then if it is it would return only pets of type cat, the problem I have is that my $request->input('cat') is returning a null. How would I correct this?
You have multiple issues in your code:
You don't seem to have a way to actually submit the form. The link in the post won't do it on it's own (unless you have some event on that link in JS)
<a>-tags don't have a value-attribute and the name-attribute means something completely different for links and is not for submitting data through forms.
A form without a method will use GET as default. You're trying to retrieve the value in PHP using $request->input() which is for POST-requests. For GET requests (which uses the query string to pass data), use $request->query().
However... you don't need the form. Just pass the value as a query parameter in the link instead:
<td>
Cat
</td>
Then in your PHP code, retrieve the value using:
if ($request->query('sort') === 'cat') {
// your code
}

Laravel - How to pass variables from view to controller with form

I'm building a request system with Laravel 7. In the index page, there is a form for user to fill in and a submit button. If the button is clicked, the data in the form will be sent to the supervisor via email. The email which the supervisor receives, all user input data will be listed along with a "Approve" button and a "Reject" button. If the "Approve" button is clicked, the user input data will be stored in the database. All user input data is stored in $data and can be accessed in email template view. So, in the email template, how do I pass the user input data and Auth::user()->id to the controller so that the storing process will start?
I read this post and it looks useful to me, but it is using <a> to do the redirection to trigger the controller. Is it possible to pass the blade variables from the <form> in the email template view to the controller, so that I can use <button>?
Update:
index.blade.php:
<form action="/sendSupervisor" method="post">
<input type="text">
<input type="text">
<button type="submit">Send</button>
</form>
web.php:
Route::post('/sendSupervisor', 'CatViewController#sendSupervisor')->middleware('auth')->middleware('verified');
CatViewController.php:
// one of the methods
public function sendSupervisor()
{
$data = request();
Mail::to('supervisor#abc.com')->send(new ApprovalMail($data));
return redirect('/');
}
approval.blade.php:
<!-- Email Template -->
User Input: {{ $data->name }}
<form action="/approve">
<button>Approve</button>
</form>
<form action="/reject">
<button>Reject</button>
</form>
An email is not a browser, and in almost every case a <form> tag will have no effect. You cannot retrieve user input from an email, however in your case if you have two buttons in the email, and that email is being sent to a user that exists in your system, AND the input you are receiving is 'accept' or 'reject' based on which button they click, this is doable.
You can have two routes that are publicly accessible and build two "buttons" with hrefs that will carry out those actions. Like:
Route::get('email/accept/{user_id}', 'EmailController#accept');
Route::get('email/reject/{user_id}', 'EmailController#reject');
Then link to those routes in your email temple like:
Accept
Reject
Then in that controller, you can resolve the user based on id in those methods, and you can carry out any logic you would like.
A note of caution: since these links need to be publicly accessible, using id's is not ideal. You should generate some sort of token to resolve the user.
A better approach:
It's better to save the user request once he post it with a column flag called "status" that holds either ("Pending", "Approved", "Rejected"), and then send an email to the supervisor
index.blade
<form action="/sendRequest" method="post">
<input type="text">
<input type="text">
<button type="submit">Send</button>
</form>
web.php
Route::get('/sendRequest', 'MyController#sendRequest)
MyController.php
public function sendRequest(Request $request){
// UserRequest table should has column 'status' with default value 'Pending'
$userRequest = UserRequest::create($request->all());
Mail::to('supervisor#abc.com')->send(new ApprovalMail($userRequest));
return redirect('/');
}
The email template should only notify the supervisor to take an action with the request, with a button 'Take action' that opens a page in the browser for him to take the action.
email-template.blade
<!-- User data displayed for example in a table -->
<a href={{ route('takeAction', $userRequest->id) }}>
<button> Take Action <button>
</a>
web.php
Route::get('/take-action/{requestId}', 'SupervisorController#takeAction')
->name('taleAction');
SupervisorController.php
public function takeAction($requestId){
$userRequest = UserRequest::find($requestId);
return view('take-action', [$userRequest]);
}
take-action.blade
<-- User data displayed for example in a table -->
<form method='POST' action={{ route('takeActionPost', $userRequest->id) }}>
#csrf
<input type='hidden' name='action' value='Approved'>
<button type='submit'>Approve</button>
</form>
<form method='POST' action={{ route('takeActionPost', $userRequest->id) }}>
#csrf
<input type='hidden' name='action' value='Rejected'>
<button type='submit'>Rejected</button>
</form>
web.php
Route::post('/take-action/{requestId}', 'SupervisorController#takeActionPost')
->name('takaActionPost');
SupervisorController.php
public function takeActionPost(Request $request, $requestId){
$userRequest = UserRequest::find($requestId);
$userRequest->update(['status', $request->action]);
}
Of course the names I'm using here are very bad, I just want to explain my idea
Add hidden input fields in the form whose values are the user data. But I think there is a better design for your system that I'll explain in a separate answer.

Passing data from view to controller in Laravel

I understand that passing record ids through the url isn't usually a good idea, but I am wondering how I can avoid it in my case:
My objective is to list job statuses on a user dashboard and allow users to adjust the status.
I create my view and pass variables to it using the session:
userController.php
public function getdashboard()
{
//reading the user information
$arrPageData['user'] = Sentry::getUser();
//reading the job interviews
$arrPageData['jobInterviews'] = JobInterview::readCurrentInterviews($this->userID);
return View::make('clients.dashboard', $arrPageData);
}
This part works great and I don't use the record id in the route. I iterate through the jobInterviews in the dashboard view. Depending up on the status listed in the DB table, I give the user options
view file: dashboard.blade.php (snippet)
#foreach ($jobInterviews as $interviews)
#if ($interviews->j == $job->id)
<tbody>
<tr>
<td>
{{$interviews->contact_name}}
#if ($interviews->status == 'interview request accepted')
Hire
#elseif ($interviews->status == 'hired')
<button id="complete" class="btn btn-info btn-small">Mark Project Complete</button>
#endif
</td>
<td>{{$interviews->status}} </td>
</tr>
</tbody>
...
The problem that I am having is that to complete the job status change, I am calling the method and passing in the record id:
Still in dashboard.blade.php
<form action="../jobs/offer/{{$interviews->interview_id}}" method="post">
This is then routed through:
Route::post('/jobs/offer/{id}','JobController#jobOffer');
Everything works as I want it to but I don't think I am doing it right from a security stand point. Is there a better way to call the jobOffer method and change the status besides using the record id in the route when getting the data from an array i've iterated through?
Thanks in advance for the help.
You may try this:
{{ Form::open(array('action' => array('JobController#jobOffer', $interviews->interview_id))) }}
<!-- Rest of the form fields -->
{{ Form::close() }}
This way you don't need to add csrf/_method input manually and by default it's METHOD would be POST so you can omit that.

Object Oriented PHP to pass message to user upon success of function

I am new to OO php so this may seem basic..
Basically I have a list of courses a user can book. I have got it so the user can remove the course from their list, but I want a message to be displayed to them after they delete. I have done something similar to what I want here:
<form name="removecourse" action="<?php bloginfo('url');?>/user/<?php echo $current_user->first_name ; ?>" method="post">
<input type="hidden" value="<?php the_id();?>" name="courseid" />
<input id="removebutton" type="submit" name="removecourse" value="Remove">
</form>
The form sends the required data to the same page, and at the top of that page is a check to see if the forms post name is present in $_POST[] like so:
if(isset($_POST['removecourse']) && !empty($_POST['removecourse'])){
$courseManager->delete_post($_POST['courseid'], $_POST['cancel-reason']);
echo $courseManager->delete_response;
};
This is where the Class and object part comes in...
public $delete_response;
function delete_post($postid, $reason){
//stuff to actually delete the post
$this->delete_response = 'Thanks, your course has been removed.';
}
So here I am adding a value to the delete_response variable and calling it above at the top of the page. This works, but when I refresh the page the message is still there as I am resubmitting the POST. I am just wondering if what I am doing is along the right track, and how to implement a Post/Redirect/Get type functionallity to stop the messaage from appearing on page refresh?
You have to check, either your course has been already deleted, is it simple as that :).
Yours displaying it again because:
if(isset($_POST['removecourse']) && !empty($_POST['removecourse'])){
//is always true when posted again.
}
You have to check the existiance

Categories