I have a list of News objects. Every news has a startDate and an expireDate. Also, every news has a state property.
If the expireDate is < date('now) then state is set to 0. state is set to 1 when expireDate > date('now).
When I render the list, for the news with state == 1 I have a toggle switch (On & Off) to activate or deactivate the news (state == 1 or state == 0 respectively). I can't get the toggle work properly.
This is my html for the buttons and my jQuery function that gives the active class to the button the user clicks:
//news.html.twig
{% if news.state == 1 %}
<div class="btn-group btn-toggle">
<button class="btn btn-xs btn-primary active">On</button>
<button class="btn btn-xs btn-default ">Off</button>
</div>
{% endif %}
<script type="text/javascript">
$('.btn-toggle').click(function() {
$(this).find('.btn').toggleClass('active');
if ($(this).find('.btn-primary').length > 0) {
$(this).find('.btn').toggleClass('btn-primary');
}
$(this).find('.btn').toggleClass('btn-default');
});
</script>
I need to integrate here the $.post call to set the state for the news when the user clicks the button.
I have in mind something like this:
$.post('{{ path('set_news_state') }}', {id: 'news.id'}, function(response) {
if (response.code == 100 && response.success){
//do something
}
}, "json");
These would be my controller:
/**
* #Route("/setNewsState/{id}", name = "set_news_state")
* #Method("POST")
**/
public function setNewsOn(Request $request, $id) {
if ($request->isXMLHttpRequest()) {
return new JsonResponse(array('data' => 'this is a json response'));
}
$repository = $this->getDoctrine()->getRepository('AppBundle:News');
$news = $repository->findOneById($id);
if ($news->getState() == 0) {
$news->setState(1);
} else {
$news->setState(0);
}
$em = $this->getDoctrine()->getManager();
$em->persist($news);
$em->flush();
return new Response();
}
How can I integrate the $.post call in my already working jQuery function?
Thanks!
You're on the right track, but it's even simpler than what you have. If you POST to the correct URL, you can get the New's entity's ID from the route parameter.
// news.html.twig
// You can supply a second argument to path() to fill in the route params.
$.post("{{ path('set_news_state', {'id': news.id}) }}").done(function(response) {
if (response.status === 'ok') {
// ...
}
});
Then in your controller
/**
* #Route("/setNewsState/{id}", name="set_news_state")
* #Method("POST")
**/
public function setNewsOn($id) {
$em = $this->getDoctrine()->getManager();
$news= $em->find('AppBundle:News', $id);
if ($news->getState() == 0) {
$news->setState(1);
} else {
$news->setState(0);
}
$em->persist($news);
$em->flush();
return new JsonResponse(array(
'status' => 'ok'
));
}
Last thing,
$news = $repository->findOneById($id); is unnecessary because find() searches for ID by default (well, not really, it searches for the primary key by default, but that's almost always going to be ID).
news = $repository->find($id); is the same, but cleaner.
Related
I want to add coupon code system in e commerce website using laravel 5.8
when i click on apply coupon button it gives me error like "Invalid argument supplied for foreach()" the problem is with that foreach loop in my controller when i remove it then it shows 0 price can anybody help me to solve this problem
here is my controller
public function applycoupon(Request $request){
$coupon = $request->input('coupon_code');
if(Coupons::where('coupon_code',$coupon)->exists())
{
$coupon = Coupons::where('coupon_code',$coupon)->first();
if($coupon->start_date<=Carbon::today()&& Carbon::today()<= $coupon->end_date){
$totalprice = "0";
$cookie_data = stripslashes(Cookie::get('shoping_cart'));
$cart_data = json_decode($cookie_data,true);
foreach ($cart_data as $itemdata){
$product = Product::find($itemdata['item_id']);
$prod_price = $product->offer_price;
// $prod_price_tax = ($prod_price*$product->tax)/100;
$totalprice = $totalprice+($itemdata['item_quantity']*$prod_price);
}
//checking Type (percentage or amount)
if($coupon->coupon_type=='Percentage')
{
$discount_price = ($totalprice/100)*$coupon->coupon_price;
}
elseif($coupon->coupon_price=='amount'||'Amount')
{
$discount_price = $coupon->coupon_price;
}
$grand_total = $totalprice-$discount_price;
return response()->json([
'discount_price' =>$discount_price,
'grand_total' =>$grand_total,
]);
}
else
{
return response()->json([
'status'=> 'coupon code has been expired',
'error_status'=>'error'
]);
}
}
else
{
return response()->json([
'status'=> 'coupon code does not exists',
'error_status'=>'error'
]);
}
}
views.blade file
<div class="card-body">
<div class="d-flex justify-content-between mb-3 pt-1">
<h6 class="font-weight-medium">Subtotal</h6>
<h6 class="font-weight-medium">${{ number_format($total, 2) }}</h6>
</div>
<div class="d-flex justify-content-between">
<h6 class="font-weight-medium">Discount</h6>
<h6 class="font-weight-medium discount_price">0.00</h6>
</div>
</div>
Route
Route::post('apply-coupons','CouponController#applycoupon');
custom js file
custom js file
//Apply coupons
$(document).ready(function () {
$('.apply-coupon-btn').click(function (e) {
e.preventDefault();
var coupon_code = $('.coupon_code').val();
if ($.trim(coupon_code).length == 0) {
error_coupon = "please enter valid coupon";
$('#error_coupon').text(error_coupon);
} else {
error_coupon = "";
$('#error_coupon').text(error_coupon);
}
if (error_coupon != '') {
return false;
}
$.ajax({
method: "POST",
url: "/apply-coupons",
data: {
'coupon_code': coupon_code,
},
success: function (response) {
if (response.error_status == 'error') {
alertify.set('notifier', 'position', 'top-right');
alertify.success(response.status);
$('.coupon_code').val('');
}
else{
var discount_price = response.discount_price;
var grand_total = response.grand_total;
$('.discount_price').text(discount_price);
$('.grand_total').text(grand_total);
}
}
});
});
});
The error Invalid argument supplied for foreach() usually occurs when the argument of foreach() is non-array value.
$cookie_data = stripslashes(Cookie::get('shoping_cart'));
$cart_data = json_decode($cookie_data,true);
foreach ($cart_data as $itemdata){
//
}
The function json_decode() return null if the json cannot be decoded. Therefore, on your code, if $cookie_data has not correct JSON format, the error can be occurred. And the variable $cookie_data is from the value of cookie shopping_cart.
In conclusion, there are two possibilities that could be the cause.
There is no assigned cookie shopping_cart on your browser.
The string value in cookie shopping_cart has incorrect JSON format.
Why don't you check the value of cookie shopping_cart running your code.
Here's the rundown. Users can view a razor page both anonymously and logged in. If they are logged in, they get certain features. In my controller, I have a boolean isAnonymous which I set to true or false depending on if there's a signed in user or not. I pass isAnonymous to my view model which gets sent to the razor page.
In the razor page, I have a javascript script tag which needs to retrieve that boolean value and, if isAnonymous is false (meaning someone is signed in), fire off one of two ajax calls to the server.
The first thing I do in my script tag is get the isAnonymous value and convert it to a JavaScript boolean with this:
var isAnonymous = #Json.Encode(Model.IsAnonymous);
after console logging, this appears to return correctly.
Then i put in my if statement. The summary here is if the user is not logged in, none of these functions nested inside the if statement should fire, because they take an ApplicationUser as part of the model. If there is no signed in user, Model.User is null and throws a Null Reference Exception. I thought putting my ajax calls inside the if statement would guard against the exception, but the the logic seems to be blowing right through the if (isAnonymous == false) and hitting those functions despite the logic. Any thoughts as to why this is happening? When isAnonymous is true, I can't have the functions fire.
if (isAnonymous == false) {
if ($('.bookmark-btn').hasClass('bookmark-story-btn')) {
addBookmark();
} else {
removeBookmark();
}
function addBookmark() {
//bookmark a story btn click event
$('.bookmark-story-btn').on('click', function () {
var storyid;
//the storyid should come as a string -
//try to parse it as an int for the controller
if (!isNaN($(this).attr('storyid'))) {
storyid = parseInt($(this).attr('storyid'))
//verify successful conversion from string to int before ajax call
if (typeof (storyid) == 'number') {
var userid = $(this).attr('userId')
var newBookmark = {
UserId: userid,
StoryId: storyid,
};
$.ajax({
url: "/api/bookmark/new",
method: "POST",
data: newBookmark,
success: function (data) {
//remove the save bookmark btn and dynamically add
//the remove bookmark btn so
//the page doesn't require a refresh
$('.bookmark-story-btn').remove();
$('.bookmark-btn-group').append("<button bookmarkId='"
+ data.Id
+ "' userId=#Model.User.Id storyId=#Model.StoryId"
+" class='btn remove-bookmark-btn bookmark-btn'>"
+"<i class='fas fa-2x fa-bookmark'></i></button>")
removeBookmark();
},
error: function (error) {
$('.page-alert').css('visibility', 'visible')
.html("Whoops. Something went wrong."
+" Adding the bookmark failed.")
//automatically close the alert-danger div
//after 2 seconds
setTimeout(function () {
$('.page-alert').css('visibility', 'hidden')
}, 3000);
}
});
}
}
});
}
function removeBookmark() {
//remove a bookmark click event
$('.remove-bookmark-btn').on('click', function () {
if (!isNaN($(this).attr('bookmarkid'))) {
bookmarkid = parseInt($(this).attr('bookmarkid'))
//verify successful conversion from string to int before ajax call
if (typeof (bookmarkid) == 'number') {
//call the ajax
$.ajax({
url: "/api/bookmark/" + bookmarkid,
method: "DELETE",
success: function (data) {
//show-hide the appropriate icons
$('.remove-bookmark-btn').remove();
$('.bookmark-btn-group').append("<button userId=#Model.User.Id"
+" storyId=#Model.StoryId class='btn bookmark-story-btn"
+" bookmark-btn'><i class='far fa-2x fa-bookmark'>"
+"</i></button>")
addBookmark();
},
error: function (error) {
$('.page-alert').css('visibility', 'visible')
.html("Whoops. Something went wrong here."
+" Removing the bookmark didn't work.")
//automatically close the alert-danger div
//after 2 seconds
setTimeout(function () {
$('.page-alert').css('visibility', 'hidden')
}, 3000);
}
})
}
}
})
}
}
You can use Request.IsAuthenticated in both the Razor view:
#if(Request.IsAuthenticated)
{
<script>
' your authenticated client side script here
</script>
}
And then check again server side when posting in your controller for example:
public ActionResult Index()
{
if(Request.IsAuthenticated)
{
//server logic here
}
}
Better still if you decorate the method with the AuthoriseAttribute the user will get an 403 Unauthorized.
You can then do something similar server side for the UserId:
[Authorize]
public ActionResult Index()
{
var userId = User.Identity.Name;
}
Then you don't even need to pass the UserId about. This is all based on using the common Identity practices:
https://learn.microsoft.com/en-us/aspnet/identity/overview/getting-started/introduction-to-aspnet-identity
I'm new on Symfony. I have a table with 5 filters and I want to keep the state of them (save the last query) when the user come back again to that page where the table is because the filters are reset.
I've being reading about how to do it, because I have no idea. I read about html web storage, about session variable but I cant find any example of how to do it, could please someone explain me which is the best method to do it and how to apply.
Here is my filterAction on my controller:
/**
* #Route("/filterFichas/", name="filterFichas")
*/
public function filterFichasAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$txtColectivo = $request->request->get('colectivo');
$txtRol = $request->request->get('rol');
$txtEstadosObjetivos = $request->request->get('EstadosObjetivos');
$txtEstadosFichas = $request->request->get('EstadosFichas');
$idPeriodo = $request->request->get('periodo');
$periodo = $em->getRepository('GOCModelBundle:Periodo')->findOneBy(array('id' => $idPeriodo));
$respuesta = array();
foreach ($periodo->getFicha() as $ficha){
$flag = true;
if($txtColectivo != "todas"){
$colectivo= $em->getRepository('GOCModelBundle:Colectivo')->findOneBy(array('nombre' => $txtColectivo ));
if($ficha->getUser()->getColectivo() != $colectivo){
$flag = false;
}
}
if($txtRol != "todas"){
$rol = $em->getRepository('GOCModelBundle:Rol')->findOneBy(array('rol' => $txtRol ));
if($ficha->getUser()->getRol() != $rol){
$flag = false;
}
}
if($txtEstadosFichas != "todas"){
if(count($ficha->getFichacontenidoestado()) > 0){
$estadoContenido = $em->getRepository('GOCModelBundle:Estadocontenido')->findOneBy(array('descripcion' => $txtEstadosFichas ));
if($ficha->getFichacontenidoestado()[count($ficha->getFichacontenidoestado()) - 1]->getEstadocontenido() != $estadoContenido){
$flag = false;
}
}else{
$flag = false;
}
}
if($txtEstadosObjetivos != "todas"){
if(count($ficha->getFichaobjetivosestado()) > 0){
$estadoObjetivos = $em->getRepository('GOCModelBundle:Estadobjetivo')->findOneBy(array('descripcion' => $txtEstadosObjetivos ));
if($ficha->getFichaobjetivosestado()[count($ficha->getFichaobjetivosestado()) - 1]->getEstadobjetivo() != $estadoObjetivos){
$flag = false;
}
}else{
$flag = false;
}
}
if($flag){
$respTemp = array(
'user' => $ficha->getUser(),
'ficha' => $ficha,
);
array_push($respuesta, $respTemp);
}
}
return $this->render('GOCFichasBundle:Default:fichasFilter.html.twig', array(
'usr' => $respuesta,
));
}
and here is my js action for the filter:
function filterFichas() {
$.blockUI({ message: '<h4><img src="{{ asset('assets/global/plugins/cubeportfolio/cubeportfolio/img/cbp-loading.gif') }}" /> Cargando datos, por favor espere...</h4>' });
var idPeriodo = $('#selectPeriodoActual').val();
$( "#tabla" ).load( "{{ path('filterFichas')}}",
{
colectivo:$( "#selectColectivo" ).val(),
rol: $( "#selectRol" ).val(),
EstadosObjetivos: $( "#selectEstadoObjetivos" ).val(),
EstadosFichas: $( "#selectEstadoFichas" ).val(),
periodo: idPeriodo
},
function() {
$.unblockUI();
});
}
How can I save the last filter action the user did so when the user come back has the last filtered table.
You can use cookies to save your filter value.
$.cookie($( "#selectEstadoFichas" ).val(), 1, { expires : 10 });
The easiest way to do this is to use the session component which is easily accessible inside your controller if it inherits the BaseController.
You can use $this->get('session') to retrieve the session service inside your controller. After that, the interface you can use to interact with it is pretty much the same as the parameter bags of the Request object you are already using (get and set methods have the same signature).
Thus, for handling a parameter, you would have to check first if it is already inside the $request->query parameter bag. If not, look inside the session for a value and if it is still not there, fallback to a default value (presumably null in your case).
You can take advantage of the second optional parameter of the get method that defines a default value in case nothing was found to do this in one line. After that, you can just save the retrieved value in the session so that it can be retrieved when the user comes back later.
$session = $this->get('session');
...
$myParam = $request->request->get('myParam', $session->get('myParam'));
if($myParam !== null)
{
$session->set('myParam', $myParam);
}
By doing that, $myParam will be null if myParam is not defined both in the request and in the session. Either way, if the retrieved value is not null, it is stored into the session for further use.
Note however that, since we are talking about sessions here, those saved parameters will only last for the duration of the session of the user. If your user closes the web browser and comes back, previously saved parameters will be lost.
The aim is to create a Favorite/Like button using the YouTube API. When a user clicks the button, the video is saved into the user's Favorite/Like playlist.
Just like how it works when you implement a Facebook like button on your own site.
This is essentially a follow up question to the fantastic solution posted by Bertrand Martel on my previous question where we aimed to add a video to the Watch Later playlist.
The working code for this particular function is:
<!-- button 1 -->
<button type="submit" data-youtube-video-id="EH3gqI2NAiE" value="Watch Later" class="ma_youtube_watch_later" name="send">
<div class="ma_youtube_watch_later_text">Watch Later</div>
</button>
<!-- button 2 -->
<button type="submit" data-youtube-video-id="0EMmKIIF-zE" value="Watch Later" class="ma_youtube_watch_later" name="send">
<div class="ma_youtube_watch_later_text">Watch Later</div>
</button>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script>
// By Bertrand Martel: https://stackoverflow.com/a/42561941/1649673
var OAUTH2_CLIENT_ID = '28993181493-c9o6hdll3di0ssvebfd4atf13edqfu9g.apps.googleusercontent.com';
var OAUTH2_SCOPES = [
'https://www.googleapis.com/auth/youtube'
];
var init = false;
var youtube_video_id = '';
var button = null;
googleApiClientReady = function() {
gapi.auth.init(function() {
window.setTimeout(checkAuth, 1);
});
}
function checkAuth() {
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: true
}, handleAuthResult);
}
// Handle the result of a gapi.auth.authorize() call.
function handleAuthResult(authResult) {
jQuery('.ma_youtube_watch_later').off('click');
jQuery('.ma_youtube_watch_later').click(function(e) {
button = this;
var youtube_video_id = jQuery(this).attr("data-youtube-video-id");
// Add a video ID specified in the form to the playlist.
function addVideoToPlaylist() {
//addToPlaylist(jQuery('#video-id').val());
addToPlaylist(youtube_video_id);
}
if (authResult && !authResult.error) {
addVideoToPlaylist();
} else {
init = true;
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: false
}, handleAuthResult);
}
return false;
});
if (authResult && !authResult.error) {
// Authorization was successful. Hide authorization prompts and show
// content that should be visible after authorization succeeds.
jQuery('.pre-auth').hide();
jQuery('.post-auth').show();
loadAPIClientInterfaces();
jQuery('#add_to_wl').click(function(e) {
button = this;
addVideoToPlaylist(self);
});
}
}
function loadAPIClientInterfaces() {
gapi.client.load('youtube', 'v3', function() {
if (init) {
init = false;
addVideoToPlaylist();
}
});
}
// Add a video to a playlist. The "startPos" and "endPos" values let you
// start and stop the video at specific times when the video is played as
// part of the playlist. However, these values are not set in this example.
function addToPlaylist(id, startPos, endPos) {
var details = {
videoId: id,
kind: 'youtube#video'
}
if (startPos != undefined) {
details['startAt'] = startPos;
}
if (endPos != undefined) {
details['endAt'] = endPos;
}
var request = gapi.client.youtube.playlistItems.insert({
part: 'snippet',
resource: {
snippet: {
playlistId: "WL",
resourceId: details
}
}
});
request.execute(function(response) {
console.log(response);
if (!response.code) {
//jQuery('#status').html('<pre>Succesfully added the video : ' + JSON.stringify(response.result) + '</pre>');
// change button text
$(button).text('Video added');
} else if (response.code == 409) {
//jQuery('#status').html('<p>Conflict : this video is already on your Watch Later playlist</p>');
// change button text
$(button).text('Already added');
} else if (response.code == 404) {
//jQuery('#status').html('<p>Not Found : this video hasnt been found</p>');
// change button text
$(button).text('Video not found');
} else {
//jQuery('#status').html('<p>Error : code ' + response.code + '</p>');
// change button text
$(button).text('Error: Try again');
}
});
}
</script>
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>
And we have a number of PHP code samples on the API docs. We also have some documentation on adding a video to playlist.
How can this be achieved using either PHP or/and javascript?
You can find Like & Favorite playlist ID with channel list endpoint with the following parameters (check this sample request) :
{
mine: true,
part: 'contentDetails'
}
You will get the list of playlists in relatedPlaylists including likes, favorites, uploads, watch later and watch history.
{
"kind": "youtube#channelListResponse",
"etag": "\"m2yskBQFythfE4irbTIeOgYYfBU/S1x68O9aSpvmndklrnSwKw_yYdE\"",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
},
"items": [{
"kind": "youtube#channel",
"etag": "\"m2yskBQFythfE4irbTIeOgYYfBU/ura_vsrPt5tCZkjjGbH3ihN3Bq4\"",
"id": "UCnQt5EmYRfX1uVYtwPNj7Dg",
"contentDetails": {
"relatedPlaylists": {
"likes": "LLnQt5EmYRfX1uVYtwPNj7Dg",
"favorites": "FLnQt5EmYRfX1uVYtwPNj7Dg",
"uploads": "UUnQt5EmYRfX1uVYtwPNj7Dg",
"watchHistory": "HL",
"watchLater": "WL"
}
}
}]
}
For WatchLater & WatchHistory, the playlistId is the same for all users (respectively WL & HL)
You can call channel list endpoint in Javascript with gapi.client.youtube.channels.list the same way as you've called the playlist insert API.
Then with the playlistId you can insert your video to another playlist than Watch Later.
In the following code, you will find 3 buttons to add different videos to Watch Later playlist, Like playlist & Favorite playlist
Javascript
Here is a live demo with the source code (as below)
Here is a fiddle. Replace your client id and add as Authorized JavaScript origins in developer console : https://fiddle.jshell.net
<!doctype html>
<html>
<head>
<title>Add to multiple playlists</title>
</head>
<body>
<input type="submit" data-youtube-video-id="EH3gqI2NAiE" data-type="WL" value="Add to Watch Later playlist" class="yt_add_to_playlist" />
<input type="submit" data-youtube-video-id="0EMmKIIF-z" data-type="likes" value="Add to Like playlist" class="yt_add_to_playlist" />
<input type="submit" data-youtube-video-id="T4ZE2KtoFzs" data-type="favorites" value="Add to Favorite playlist" class="yt_add_to_playlist" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script>
var OAUTH2_CLIENT_ID = '28993181493-c9o6hdll3di0ssvebfd4atf13edqfu9g.apps.googleusercontent.com';
var OAUTH2_SCOPES = [
'https://www.googleapis.com/auth/youtube'
];
var init = false;
var button = null;
googleApiClientReady = function() {
gapi.auth.init(function() {
window.setTimeout(checkAuth, 1);
});
}
function checkAuth() {
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: true
}, handleAuthResult);
}
// Handle the result of a gapi.auth.authorize() call.
function handleAuthResult(authResult) {
jQuery('.yt_add_to_playlist').off('click');
jQuery('.yt_add_to_playlist').click(function(e) {
button = this;
if (authResult && !authResult.error) {
addToPlaylist($(this).attr("data-youtube-video-id"), $(this).attr("data-type"));
} else {
init = true;
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: false
}, handleAuthResult);
}
return false;
});
if (authResult && !authResult.error) {
// Authorization was successful. Hide authorization prompts and show
// content that should be visible after authorization succeeds.
jQuery('.pre-auth').hide();
jQuery('.post-auth').show();
loadAPIClientInterfaces();
jQuery('#add_to_wl').click(function(e) {
button = this;
addToPlaylist($(this).attr("data-youtube-video-id"), $(this).attr("data-type"));
});
}
}
function loadAPIClientInterfaces() {
gapi.client.load('youtube', 'v3', function() {
if (init) {
init = false;
addToPlaylist($(button).attr("data-youtube-video-id"), $(button).attr("data-type"));
}
});
}
function addToPlaylist(videoId, playlistType) {
console.log("add to playlist type : " + playlistType);
if (playlistType != "WL" && playlistType != "HL") {
var request = gapi.client.youtube.channels.list({
mine: true,
part: 'contentDetails'
});
request.execute(function(response) {
var playlistId = response.result.items[0].contentDetails.relatedPlaylists[playlistType];
if (typeof playlistId != 'undefined') {
console.log("found playlist id : " + playlistId);
insertToPlaylist(videoId, playlistId);
} else {
console.log("playlist not found");
}
});
} else {
insertToPlaylist(videoId, playlistType);
}
}
function insertToPlaylist(videoId, playlistId) {
var details = {
videoId: videoId,
kind: 'youtube#video'
};
var request = gapi.client.youtube.playlistItems.insert({
part: 'snippet',
resource: {
snippet: {
playlistId: playlistId,
resourceId: details
}
}
});
request.execute(function(response) {
console.log(response);
if (!response.code) {
$(button).val('Video added');
} else if (response.code == 409) {
$(button).val('Already added');
} else if (response.code == 404) {
$(button).val('Video not found');
} else {
$(button).val('Error: Try again');
}
});
}
</script>
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>
</body>
</html>
Replace OAUTH2_CLIENT_ID with your own client ID
In the API response, the status code is checked in case the video is not found (404). The 409 status code is returned if the video is already in the playlist but only for watch later playlist (adding an existing video to like/favorite playlist will not changed anything though)
PHP
The same as before, based on google-api php sample :
install composer : see instructions
install google-api client :
composer require google/apiclient:~2.0
The php script multi-playlist.php :
<?php
/**
* Library Requirements
*
* 1. Install composer (https://getcomposer.org)
* 2. On the command line, change to this directory (api-samples/php)
* 3. Require the google/apiclient library
* $ composer require google/apiclient:~2.0
*/
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
throw new \Exception('please run "composer require google/apiclient:~2.0" in "' . __DIR__ .'"');
}
require_once __DIR__ . '/vendor/autoload.php';
session_start();
$response = "";
/*
* You can acquire an OAuth 2.0 client ID and client secret from the
* {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
* For more information about using OAuth 2.0 to access Google APIs, please see:
* <https://developers.google.com/youtube/v3/guides/authentication>
* Please ensure that you have enabled the YouTube Data API for your project.
*/
$OAUTH2_CLIENT_ID = 'YOUR_CLIENT_ID';
$OAUTH2_CLIENT_SECRET = 'YOUR_CLIENT_SECRET';
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'],
FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
// Check if an auth token exists for the required scopes
$tokenSessionKey = 'token-' . $client->prepareScopes();
if (isset($_GET['code'])) {
if (strval($_SESSION['state']) !== strval($_GET['state'])) {
die('The session state did not match.');
}
$client->authenticate($_GET['code']);
$_SESSION[$tokenSessionKey] = $client->getAccessToken();
header('Location: ' . $redirect);
}
if (isset($_SESSION[$tokenSessionKey])) {
$client->setAccessToken($_SESSION[$tokenSessionKey]);
}
// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
try {
$videoId = "";
if (isset($_GET['video'])){
$videoId = $_GET['video'];
}
else if(isset($_SESSION['video'])){
$videoId = $_SESSION['video'];
}
if (isset($_GET['action'])){
$action = $_GET['action'];
}
else if(isset($_SESSION['action'])){
$action = $_SESSION['action'];
}
if(isset($videoId) && isset($action) && !isset($_GET['state'])) {
file_put_contents('php://stderr', print_r("adding video to watch later playlist " . $videoId . "\n", TRUE));
if ($action == "Add to Watch Later playlist") {
$playlistId = "WL";
}
else {
$listResponse = $youtube->channels->listChannels("contentDetails", array(
'mine' => true
));
if (!empty($listResponse)) {
if ($action == "Add to Like playlist"){
$playlistId = $listResponse['items'][0]['contentDetails']['relatedPlaylists']['likes'];
}
else if ($action == "Add to Favorite playlist"){
$playlistId = $listResponse['items'][0]['contentDetails']['relatedPlaylists']['favorites'];
}
}
}
if (isset($playlistId)){
// 5. Add a video to the playlist. First, define the resource being added
// to the playlist by setting its video ID and kind.
$resourceId = new Google_Service_YouTube_ResourceId();
$resourceId->setVideoId($videoId);
$resourceId->setKind('youtube#video');
// Then define a snippet for the playlist item. Set the playlist item's
// title if you want to display a different value than the title of the
// video being added. Add the resource ID and the playlist ID retrieved
// in step 4 to the snippet as well.
$playlistItemSnippet = new Google_Service_YouTube_PlaylistItemSnippet();
$playlistItemSnippet->setTitle('First video in the test playlist');
$playlistItemSnippet->setPlaylistId($playlistId);
$playlistItemSnippet->setResourceId($resourceId);
// Finally, create a playlistItem resource and add the snippet to the
// resource, then call the playlistItems.insert method to add the playlist
// item.
$playlistItem = new Google_Service_YouTube_PlaylistItem();
$playlistItem->setSnippet($playlistItemSnippet);
$playlistItemResponse = $youtube->playlistItems->insert(
'snippet,contentDetails', $playlistItem, array());
$response = json_encode($playlistItem);
}
else{
$response = "no playlist selected";
}
$_SESSION['video'] = "";
$_SESSION["action"] = "";
}
else{
file_put_contents('php://stderr', print_r("no video was specified", TRUE));
}
} catch (Google_Service_Exception $e) {
$response = htmlspecialchars($e->getMessage());
} catch (Google_Exception $e) {
$response = htmlspecialchars($e->getMessage());
}
$_SESSION[$tokenSessionKey] = $client->getAccessToken();
} else {
if(isset($_GET['video'])){
$_SESSION["video"] = $_GET['video'];
$_SESSION["action"] = $_GET['action'];
// If the user hasn't authorized the app, initiate the OAuth flow
$state = mt_rand();
$client->setState($state);
$_SESSION['state'] = $state;
$authUrl = $client->createAuthUrl();
header('Location: ' . $authUrl);
}
}
?>
<!doctype html>
<html>
<head>
<title>Add to playlists</title>
</head>
<body>
<div>
<form id="form" action="multi-playlist.php"">
<input type="hidden" name="video" value="EH3gqI2NAiE">
<input name="action" type="submit" value="Add to Watch Later playlist" />
<input name="action" type="submit" value="Add to Like playlist" />
<input name="action" type="submit" value="Add to Favorite playlist" />
</form>
<div>
<?php echo $response ?>
</div>
</div>
</body>
</html>
For this PHP version, note that in addition to the video id in the current session $_SESSION["video"], the target action is also stored in $_SESSION["action"] to be able to determine which playlist to use. Playlists are retrieved with channel list endpoint with $youtube->channels->listChannels.
Note that it can take some time for the video to appear in the playlists (sometimes a few seconds)
Please help. I've been stuck on the same problem for about two weeks now. So I downloaded the advanced login master script from Github and customized it a bit.
Advanced login script
Everything was going fine until I created a Post class and tried adding an ajax form to the "views/logged_in.php" file. The form validation error messages stopped showing up correctly. I'm trying to check if the input field is empty for the form before submitting the form via Ajax. I'm not used to the way this script has been set up. The index file seems to call the classes. But when I try to add ajax it throws me off completely.
Can somebody please show me the proper way to add a simple ajax form to this script within the "views/Logged in.php" file while displaying an error message if the input field is empty?
P.S. I want to display a PHP error, not a Javascript error. In my Post class I have an array for errors and messages.
Here is my javascript ajax code.
$('form.ajax').on('submit', function() {
var that = $(this),
url = that.attr('action'),
type = that.attr('method'),
data = {};
that.find('[name]').each(function(index, value) {
var that = $(this),
name = that.attr('name'),
value = that.val();
data[name] = value;
});
$.ajax({
url: url,
type: type,
data: data,
success: function(response) {
$("form.ajax")[0].reset();
console.log(response);
}
});
return false;
});
website.com/views/logged_in.php
<form action="<?php echo BASE_URL; ?>contact.php"` method="post" class="ajax">
<div class="new_post_header">
<div class="new_post_avatar"><img src="img/profile_pic_1.png" style="width:40px; height:40px;" /></div>
<textarea name="post_text" id="message" class="new_post_textarea" placeholder="Give a tip"></textarea>
</div><!--.new_post_header-->
<div id="new_post_options">
<div class="icon-camera post_options_icon"></div>
<div class="icon-camcorder post_options_icon"></div>
<div class="icon-tag post_options_icon"></div>
<button name="submit" type="submit" class="post_post_button">Post</button>
<a class="privacy_post_option" id="post_privacy_toggle">
<div class="icon-earth-grid privacy_option_icon"></div>
Public
<div class="icon-more-arrow privacy_option_arrow"></div>
</a>
</div><!--#new_post_options-->
</form><!--.ajax-->
website.com/classes/Post.php class
<?php
class Post
{
/**
* #var object $db_connection The database connection
*/
private $db_connection = null;
/**
* #var string $logged_in_user_id the poster's id variable
*/
public $logged_in_user_id = null;
/**
* #var string $post_text The post text variable
*/
public $post_text = "";
/**
* #var array collection of error messages
*/
public $errors = array();
/**
* #var array collection of success / neutral messages
*/
public $messages = array();
/**
* Checks if database connection is opened and open it if not
*/
private function databaseConnection()
{
// connection already opened
if ($this->db_connection != null) {
return true;
} else {
// create a database connection, using the constants from config/config.php
try {
// Generate a database connection, using the PDO connector
// #see http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
// Also important: We include the charset, as leaving it out seems to be a security issue:
// #see http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers#Connecting_to_MySQL says:
// "Adding the charset to the DSN is very important for security reasons,
// most examples you'll see around leave it out. MAKE SURE TO INCLUDE THE CHARSET!"
$this->db_connection = new PDO('mysql:host='. DB_HOST .';dbname='. DB_NAME . ';charset=utf8', DB_USER, DB_PASS);
return true;
// If an error is catched, database connection failed
} catch (PDOException $e) {
$this->errors[] = MESSAGE_DATABASE_ERROR;
return false;
}
}
}
/**
* creates a new post in the databse
*/
public function submitPost($logged_in_user_id, $post_text)
{
// remove extra space on post text
$post_text = trim($post_text);
// if the post text is empty
if (empty($post_text)) {
// show the errors
$this->errors[] = MESSAGE_USERNAME_EMPTY;
} else if ($this->databaseConnection()) {
// write new post data into database
$query_new_post_insert = $this->db_connection->prepare('INSERT INTO posts (poster_id, post_text, post_date) VALUES(:poster_id, :post_text, NOW())');
$query_new_post_insert->bindValue(':poster_id', $logged_in_user_id, PDO::PARAM_INT);
$query_new_post_insert->bindValue(':post_text', $post_text, PDO::PARAM_STR);
$query_new_post_insert->execute();
// id of new post
$post_id = $this->db_connection->lastInsertId();
// return the id of the last post to be added to database
return $post_id;
}
}
/**
* creates a new post in the databse
*/
public function getPost($logged_in_user_id)
{
// remove extra space on post text
$post_text = trim($post_text);
if ($this->databaseConnection()) {
// write new post into database
$query_new_post_insert = $this->db_connection->prepare('INSERT INTO posts (post_text) VALUES(:post_text)');
$query_new_post_insert->bindValue(':post_text', $post_text, PDO::PARAM_STR);
$query_new_post_insert->execute();
// id of new post
$post_id = $this->db_connection->lastInsertId();
// return the id of the new post
return $post_id;
}
}
}
website.com/contact.php
<?php
// start the seesion so that you can access the $_SESSION variable
session_start();
// put the current logged in user's id in a variable
$logged_in_user_id = $_SESSION['user_id'];
// include the config
require_once('config/config.php');
// include the to-be-used language, english by default. feel free to translate your project and include something else
require_once('translations/en.php');
// load the post class
require_once('classes/Post.php');
// create the post object
$post = new Post(
);
if (isset($_POST['post_text'])) {
// put the post text in a variable
$post_text = $_POST['post_text'];
// put the returned id from the submited post into a variable
$post_id = $post->submitPost($logged_in_user_id, $post_text);
}
?>
Hi i have make your submit button as button and onclick i have called ajax function
function test1()
{
var that = $('.ajax'),
url = 'contact.php',
type = 'POST',
data = {};
that.find('[name]').each(function(index, value) {
var that = $(this),
name = that.attr('name'),
value = that.val();
if(value=='')
{
alert("please enter value of " +name);
}
data[name] = value;
});
$.ajax({
url: url,
type: type,
data: data,
success: function(response) {
if(response==2)
{
alert("plaese enter text");
or
$('.error').html("plaese enter text");
}
if(response==1)
{
$("form.ajax")[0].reset();
}
console.log(response);
}
});
return false;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="post" class="ajax">
<div class="new_post_header">
<div class="new_post_avatar"><img src="img/profile_pic_1.png" style="width:40px; height:40px;" /></div>
<textarea name="post_text" id="message" class="new_post_textarea" placeholder="Give a tip"></textarea>
</div><!--.new_post_header-->
<div id="new_post_options">
<div class="icon-camera post_options_icon"></div>
<div class="icon-camcorder post_options_icon"></div>
<div class="icon-tag post_options_icon"></div>
<button type="button" onclick="return test1();" class="post_post_button">Post</button>
<a class="privacy_post_option" id="post_privacy_toggle">
<div class="icon-earth-grid privacy_option_icon"></div>
Public
<div class="icon-more-arrow privacy_option_arrow"></div>
</a>
</div><!--#new_post_options-->
</form><!--.ajax-->
A very simplified way of doing this would be:
$('form.ajax').on('submit', function() {
var empty = true;
$("form.ajax input").each(function(){ // check each input
var val = $(this).val();
if(!$.trim(val) == ""){ // if the inputs are not empty
empty = false; // allow ajax to be submitted
}
});
if(empty){
alert("Input is empty!"); // alert that an input is empty
} else {
// ajax goes here
}
return false; // prevent form post
});
Note: This procedure also works if the inputs contain JUST white space (no text). I would suggest checking for this on the server-side too, not just the client-side (as this is editable within the (potential) attackers) browser.