amp-form session based backend and 3rd party cookies - cookies

Trying to grok this e-commerce scenario...
I build an amp product page in amp that has the new amp-form
The add to cart button is an XHR to my backend (that is session based, using
cookies by default)
User searches for product and results take them
to my amp product page, but they've never been to my site
They submit the add to cart form
the CORS preflight makes it's way to my backend, and i set all the correct allows as per https://github.com/ampproject/amphtml/blob/master/spec/amp-cors-requests.md
Now the actual request is made... backend initializes a session,
returns session identifier as a cookie, but since user never went to
my site...just the google amp cache it's treated as a 3rd party
cookie and browser discards it (cause user disables 3rd party cookies)
users session is lost, as is their add to cart action
So the question is, how do i keep the session around and the item in the cart?
Am i missing something? is there a trick i'm not seeing?
appreciate any insights.

Associating the shopping cart with the CLIENT_ID would be the best way to solve this problem. Unfortunately, transferring the CLIENT_ID via forms is not yet supported in AMP. It's currently being implemented, you can watch this issue for the current status.
Here is an approach that works right now: the idea is to encode the shopping cart content into a string that is returned in the form result. This way we can generate "View Cart" and "Checkout" links including the shopping cart content. Once the user clicks on one of those links, you can create the actual shopping cart in your backend and store the user id in a cookie.
For example:
<form action-xhr="/add-to-cart" method="POST">
<input type="hidden" name="itemId" value="headphones-123">
<!-- Hide after form submit success -->
<input type="submit" name="add" value="Add to Cart">
<div submit-success>
<template type="amp-mustache">
<!-- shopping cart contents, e.g headphones-123 -->
{#shoppingCartContent}
View In Cart
Checkout
{/shoppingCartContent}
</template>
</div>
<div submit-error>
<template type="amp-mustache">
{{message}} <!-- e.g. Only 2 Headphones are left. -->
</template>
</div>
</form>
The disadvantage of this approach is that the shopping cart will be lost when the user leaves the page without viewing the cart first. This will be solved once the CLIENT_ID can be passed via amp-form.

I also know very limited info about AMP pages but I suggest that you please read through the use of User identification and try using an AMP-generated client ID. As mentioned in the documentation:
By default, AMP will manage the provision of a client ID whether the page is accessed from the publisher's original website or through a cache.
Likewise, learn more about client ID substitution, including how to add an optional user notification ID, in Variables supported in AMP analytics.
Hope that helps!

Related

Can I send requests to the server from HTML rendered in email?

I am trying to implement the following functionality.
The server sends an email to a user who doesn't necessarily have an account in the server.
In the email, the user is asked to rate a certain model (send a request to the server).
Can I make it in such a way that the user can click the button and doesn't get redirected to some other page, but sends the request directly to the server.
<div>
<p> Hi {{ user }}, </p>
This e mail is to kindly ask you to rate {{ job_seeker }}, who previously
worked with you.
Please rate him from 1 to 3 below.
<button onclick="some function that wont work in email">1</button>
<button>2</button>
<button>3</button>
</div>
I am using django.
NO, you cant execute JavaScript in email templates.
Due to serious security issues, most of the email clients block JavaScript from executing. that's why your redirection script doesn't work.
the solution is to use an <a> tag with a URL that specifies the page link instead of <button>.

Django redirect page does not update the view

I'm using the Django Framework on Google App Engine.
I have multiple forms on the same view, to submit to different URL.
Trouble is after I get a form submitted: even if the called method update the datastore and some data, the previous page (where the forms are put in) is not refreshed, showing the updated data.
I could solve this problem using jQuery or some javascrip framework, appending dinamically content returned by the server but, how to avoid it?
Suggestions?
Am I wrong somewhere?
A part of "secure.html" template
<form action="/addMatch" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Matches:
<br />
{% for m in matches%}
{{m.description}} ---> {{m.reward}}
{% endfor%}
the "/addMatch" URL view:
def addMatch(request):
form = MatchForm(request.POST)
if form.is_valid():
user = User.all().filter('facebookId =', int(request.session["pbusr"]))
m = Match(user=user.get(),description =form.cleaned_data["description"],reward=form.cleaned_data["reward"])
m.save()
return HttpResponseRedirect("/secure/")
else:
logging.info("Not valid")
return HttpResponseRedirect("/secure")
The view method whose seems not working:
#auth_check_is_admin
def secure(request):
model={}
user = User.all().filter('facebookId =', int(request.session["pbusr"]))
u = user.get()
if (u.facebookFanPageId is not None and not u.facebookFanPageId == ""):
model["fanPageName"] = u.facebookFanPageName
model["form"] = MatchForm()
model["matches"] = u.matches
else:
....
return render(request,"secure.html",model)
Francesco
Based on what you posted, it seems like you're redirecting properly and are having database consistency issues. One way to test this would be to look at the network tab in the Google Chrome developer tools:
Click on the menu icon in the upper right
Click on "Tools"
Click on "Developer Tools"
Click on "Network" in the thing that opened up at the bottom of the screen.
Now, there will be a new entry in the network tab for every request that your browser sends and every response it receives. If you click on a request, you can see the data that was sent and received. If you need to see requests across different pages, you might want to check the "Preserve log" box.
With the network tab open, go to your page and submit the form. By looking at the network tab, you should be able to tell whether or not your browser issued a new GET request to the same URL. If there is a new request for the same page but that request has the old content, then you have a datastore consistency issue. If there was NOT a new request that yielded a response with the data for the page, then you have a redirect issue.
If it turns out that you have a datastore consistency issue, then what's happening is the data is being stored, but the next request for that data might still get the old data. To make sure that doesn't happen, you need what's called "strong consistency."
In a normal App Engine project, you get strong consistency by putting entities in the same entity-group and using ancestor queries. I'm not certain of what database/datastore you're using for Django and how the different database layers interact with App Engine's consistency, so this could be wrong, but if you can give your users the right key and then fetch them from that key directly (rather than getting all users and filtering them by key), you might get strong consistency.

Getting dropdown value from template django

I am facing an issue working with django ( using shopcart ). I want to add a select options field to change dynamically an item suscription in the cart, but I am not getting the value selected from the template.
In my template where I display the cart I have :
<form action="" method="GET">{%csrf_token%}
<select name="suscr" title="suscr">
<option value="" selected>Suscribe</option>
<option value="1" name="suscr" >Weekly</option>
<option value="2" name="suscr">Monthly</option>
</select>
</form>
I want to select an option and then, if I press 'Checkout' to have the cart updated.
Appart from that, I believe its missing a method modifying the item in cart.py.
Any ideas would help.
Thanks
The above form is inside a loop
{% for item in cart %}
What i propose you to do is not python-oriented but all javascript for the most part as, from the description, we assume that what you are dealing with is going all at the client-side.
As you are dealing with a shopping cart, what i'd do is storing what the user is checking in a sessionStorage so that the information would persist while the user navigates through your website even with multiple tabs. As the user might just be "walking around" you shopping website, there's no need to push things to the database without even knowing if the user wants that. Just remove the form and keep with the select, then you get what the user selected appending an attribute to select: <select onchange=my_function(this.value)>...</select> and then, inside my_functionin a script change whatever you want to the page.
When the user enters the shopping cart page you show him what he selected so far getting the items from the sessionStorageand then, if he/she confirms that wants to buy, then submit a form to the server-side, update the database and proccess that as your workflow states.
tl;dr: store the options in sessionStorage, just post to the server at the end.
For help on the server-side update your question with more info about the cart.py

Form action and its usage in Django

First Quesiton:
This form submits to demo_form?name=ABC
<form action="demo_form" method="get">
name: <input type="text" name="name"><br>
<input type="submit" value="Submit">
</form>
Is there a way to make it submit to demo_form/ABC/?
Second Question:
Even if users don't use my form, if they use a web crawler to simply visit demo_form?name=ABC or demo_form/ABC/, it would yield the same result. I want to prevent that. What's the best way of making those two URLs only valid if the user submit the name via my form? I am learning django so hopefully the solution would work with django framework.
Thanks in advance!
Is there a way to make it submit to demo_form/ABC/?
You could intercept the submission in JavaScript, construct the URL manually, then set location. That would break if JS wasn't available.
More sanely, you could send an HTTP 301 redirect response when you get the request for demo_form?name=ABC
What's the best way of making those two URLs only valid if the user submit the name via my form?
Generally speaking, visiting a form should not be a pre-requisite for anything involving a GET request. A large portion of the point of GET is that the results are bookmarkable, linkable, etc.
It would be more understandable if it was a POST request, as those are intended to change data on the server and you will want to protect against CSFR. The standard protection against CSRF is a token stored in the form and in a cookie

like detail page inside timeline page tab

I have a facebook timeline page tab app that's running inside an IFRAME on a fan page.
On the main page of the app, we show 10 jobs and users can click through to the detail page of one single book.
We want to add a LIKE button on those detail pages, so that users on facebook can like and share that job in their stream.
The app is totally dynamic so different customers can install the app on their fan page and list their own jobs. (ex. coca-cola installs it on his coca-cola page and lists jobs within the company. then microsoft installs it as well and does the same)
The problem concerns og:metatags and redirection of the liked detail page link, right inside the right facebook company page and relative right detail page showing the job.
I can get these two things done and working but not at the same time:
A. Facebook gets correctly the og:metatags in the head section, with image, title, description when I use the following implementation of the like button (without "data-href" extra attribute)
<div class="fb-like"
data-send="false"
data-layout="button_count"
data-show-faces="false"
data-action="like"
data-font="arial">
</div>
The problem is that not specifying the data-href attribute (and the og:url meta is totally ignored) this is gonna create a link to the current page => intended current page inside an iframe => so the result will be that when you click the shared job on facebook you will be redirected NOT inside the facebook app -right page -right detail page, but to the detail page on the server that hostes the app.
B. If I instead specify the data-href attribute
<div class="fb-like"
data-href=<%= "http://www.facebook.com/pages/:page/#{session[:fb_page_id]}?v=app_XXXXXXX&app_data=#{#job_details.job_id}" %>
data-send="false"
data-layout="button_count"
data-show-faces="false"
data-action="like"
data-font="arial">
</div>
Doing this I can get the right link posted on facebook (so then using &app_data attribute) I can get the perfect redirection working.
BUT on the downside, the og:metatags are totally ignored and instead facebook picks the page tab metatags (top iframe that hostes the pagetab app) and so I get posted on facebook a crap link that tells about a page on facebook with the page app picture. And the even bigger downside is that when you like a job on the app, all the jobs appear to be liked as well (basically the iFrame app becomes the liked page... instead of being the job detail page picked as liked page)
Is out there any genius that knows how to sort this out? I need to get the A an B working at the same time to get the requested result!!!!
Please help!!! :(
I've found the solution myself.
Like button => use href and ref attributes, especially put on the ref the id of your facebook fan page. Passing the current page url will also load and share correctly the og:metatags.
<div class="fb-like"
data-send="false"
data-show-faces="false"
data-layout="button_count"
data-font="arial"
data-action="recommend"
href=<%= "https://app.com/jobs/job_details.job_id" %>
ref=<%= FB_PAGE_ID %>>
</div>
Once you pass the ref attribute to facebook, on your wall the link will be posted by facebook with an extra query string appended with in particular the "fb_ref" parameter:
for example a button with parameters:
href=<%= "https://app.com/jobs/job_details.job_id" %>
and
ref=<%= 332325142248470 %>
becomes:
https://app.com/jobs/a0Ed000000a54bkEAA?fb_ref=332325142248470&fb_source=profile_multiline
when the user clicks the link we want to be redirected back right inside the correct page tab app and right job details page. To achieve this we set up into the controller/show action (that in ruby corrisponds to controller_name/id) a new redirection, remembering that ref will put inside a query string after our href link:
if params[:fb_ref]
redirect_to "http://www.facebook.com/pages/:page/#{params[:fb_ref]}?v=app_xxxxx&app_data=#{params[:id]}"
end
As you can see we create a new dynamic url that will use the "app_data" parameter of the facebook "signed_riquest" (http://developers.facebook.com/docs/authentication/signed_request/) in order to pass to our application the right detail page to be visualized and also redirect us to the right facebook page.
once done this we have just to manage correctly the new app_data parameter that comes now with the signed_request. In my case in one of my main controller I've used:
if fb_signed_request[:app_data]
redirect_to "/jobs/#{session[:app_data]}"
end
And we will see our app loading the right page and the right job detail page!
Hope is gonna help other people!