Integrating a Fable/Elmish app with Stripe checkout - f#

Edit: Someone on gitter has suggested this:
https://stripe.com/docs/recipes/elements-react
...so I'm trying that and will report back here.
I'm creating a Fable/Elmish app which will take payments via the Stripe 'Checkout' api (https://stripe.com/docs/checkout/aspnet). Stripe mandates that you get the checkout.js script on demand (i.e. not via Node). When placed within a form element and provided with a few values via data- attributes, the script adds a payment button to your page. For example here is a working .cshtml view from a an ASP dotnet app:
#using Microsoft.Extensions.Options
#inject IOptions<StripeSettings> Stripe
<form action="/Home/Charge" method="POST">
<article>
<label>Amount: $5.00</label>
</article>
<script src="//checkout.stripe.com/v2/checkout.js"
class="stripe-button"
data-key="#Stripe.Value.PublishableKey"
data-locale="auto"
data-description="Sample Charge"
data-amount="500"
data-billing-address=true>
</script>
</form>
I am trying to do the equivalent in my Elmish app, which I think boils down to this:
let view (model : Model) (dispatch : Msg -> unit) =
let payScript =
script
[
Src "//checkout.stripe.com/v2/checkout.js"
Class "stripe-button"
Data ("key","pk_test_REDACTED") // Should come from config via the model
Data ("locale", "auto")
Data ("description", "Sample charge")
Data ("amount", "999")
Data ("billing-address", true)
]
[]
div []
[
Text "This is the payment area"
form [
Action "/Home/Charge"
Method "POST"
]
[
article []
[
label [] [ Text "Amount £9.99" ]
]
payScript
]
]
When rendered this appears like this on the client:
This is the payment area
Amount £9.99
* expected button here *
...but the button hasn't been created, which suggests to me that the script hasn't run, or that it hasn't found the form to insert the button. The script element does appear within the form in the rendered page:
<div>This is the payment area>
<form action="/Home/Charge" method="POST">
<article><label>Amount £9.99</label></article>
<script src="//checkout.stripe.com/v2/checkout.js" class="stripe-button" data-key="pk_test_REDACTED" data-locale="auto" data-description="Sample charge" data-amount="999" data-billing-address="true">
</script>
</form>
</div>
I don't see any browser errors on the Chrome console, other than the socket errors one usually gets. (I've back-to-backed with and without the checkout script and there are two identical errors in each case.)
If I place the script and form within my Index.htmlwith hardwired values, the button does appear, though obviously not in the right place.
What am I missing? Is there something about being within an Elmish app that stops external scripts being executed?
Many thanks!

Related

Is there a way to get a QR code image with Google Apps Script using the POST method of the Google Charts API?

I am using a Google Script to generate tickets to an event, and the ticket includes a QR code which goes to a pre-filled Google Form link. Since it's pre-filled, the string is quite long, and the Google Charts API for creating QR codes will not accept a string of text that long using a GET request, but I can't find any documentation of how to code the POST request into Apps Script. How do I generate a POST request in Apps Script that will return an image of the QR code which I can then insert into the document?
I already tried the GET request, and it truncates the URL before encoding it into a QR code. That gets me to the Google Form, but not the pre-filled version that the link generates (actually pretty smart on Google's part to have it truncate the string in a place that still gives a usable URL, but that's for another day...)
I have also tried the HtmlService to render the QR code using the POST method with the Charts API in an HTML form that automatically submits on the loading of that HTML. If I use showSidebar(), this will open the image in a new tab, but I haven't figured out how to return that image so that it can be inserted into the document.
I've also tried creating a blob with the HTML and then saving the blob as a PNG, but from the research I've done, the .getAs() method doesn't render images when converting the HTML.
The renderQR function:
function renderQR(inputUrl) {
var html = HtmlService.createTemplateFromFile('QREncode.html');
html.url = inputUrl;
var rendered = html.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setHeight(300)
.setWidth(300);
return rendered;
}
The QREncode.html file:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script type='application/javascript'>
// Send the POST when the page is loaded,
// which will replace this whole page with the retrieved chart.
function loadGraph() {
var frm = document.getElementById('post_form');
if (frm) {
frm.submit();
}
}
</script>
</head>
<body onload="loadGraph()">
<form action='https://chart.googleapis.com/chart' method='POST' id='post_form'>
<input type='hidden' name='cht' value='qr' />
<input type='hidden' name='chl' value='<?= url ?>' />
<input type='hidden' name='chs' value='300x300' />
<input type='submit'/>
</form>
</body>
</html>
When I treat the return from the renderQR() function as an image, Apps script gives an error saying that it is "Invalid image data", which makes sense -- but how do I convert it into an image, or is there a better or simpler way I could be doing this?
You need to get the qr code in the Apps Script, not in the browser:
var imageData = UrlFetchApp.fetch('https://chart.googleapis.com/chart', {
'method' : 'post',
'payload' : {
'cht': 'qr',
'chl': 'https://google.com',
'chs': '300x300'
}}).getContent();
For those looking for a formula solution (without Apps Script)
Reference: https://www.benlcollins.com/spreadsheets/qr-codes-in-google-sheets/
Solution:
=IMAGE("https://chart.googleapis.com/chart?chs=250x250&cht=qr&chl="&ENCODEURL(A1))

How to fix parsing errors in form POST request in Rocket?

I am making a very simple web app using the rust Rocket framework. I have a very simple HTML file that has a form, as follows:
<form action="/search" method="post" accept-charset="utf-8">
Search Term:<input type="text" name="searchterm">
<input type="submit" value="search">
</form>
Next, here are my rocket functions to deal with the requests. I have a get function that spits out index.html when accessing "/", then for my form, I have the following functions:
#[derive(FromForm)]
pub struct Request<'r> {
payload: &'r RawStr,
// we can add more if we want later on, for other form options...
}
#[post("/search", data = "<data>")]
pub fn process(data: Form<Request>) -> Result<Redirect, String> {
if data.payload == "Hello!" {
Ok(Redirect::to("/search/Hello"))
} else {
Err(format!("Unknown search term, '{}'.", data.payload))
}
}
Then, this is to response to the GET requests:
#[get("/search/<term>")]
pub fn response(term: &RawStr) -> String {
format!("You typed in {}.", term)
}
Like I said, very simple, very barebones, just trying to tiptoe into both Rust and Web Apps at the same time. I do not have much experience in either. My issue is, when using the field presented to the user in my html file, the server returns an error:
POST /search application/x-www-form-urlencoded:
=> Matched: POST /search (process)
=> Error: The incoming form failed to parse.
=> Outcome: Failure
=> Warning: Responding with 422 Unprocessable Entity catcher.
=> Response succeeded.
If I go directly, to localhost:8000/search/Hello! I can see that my GET response works. But if I use my form it refuses to parse. What am I doing wrong? I am simply attempting to make a web app that takes an input, and based on that input, returns something. Website redirection, web scraping, I am not sure on the specifics of functionality yet, but I need to be able to type something into the form and obtain it for use in my rust code later. Any help would be appreciated!
I think the problem is that your form parameter name (<input type="text" name="searchterm">) doesn't match with your struct field name (payload). If you rename one or the other so they would match, your form should work.

How to fix Meteor being unreliable on mobile

I'm not even sure where to start. I have a relatively simple meteor app (http://www.vertexshaderart.com). It's using iron router for routes. The main route / seems like a pretty normal situation. Show the 8 newest posts. Show the 8 most liked posts sort: {likes: -1}.
When I try to view on my phone it only works about 1 out 5 times, maybe less. The site shows up, the main template is clearly rendered and at least one child rendered but the templates waiting for data never show up. They have {{#if Template.subscriptionsReady}} wrappers. Or rather the parts inside the wrapper never show up. I'm guessing the subscriptions never complete on mobile for some reason. In fact the entire 10+ minutes I've been typing and editing this response I've had my phone sitting beside my computer trying to load the page. It's been sitting there loading for > 10 mins, the data spinner in the iOS status bar spinning constantly.
But, when I try to debug it it always works (or at least so far). It works fine in the iPhone Simulator. It works fine if I connect directly to my dev machine over WiFi. Like I said it works fine 1 or of 5 times or so on mobile. I've tried connecting to a debugger USB and then remote debug Safari but it always seems to work when I do that.
You might think it's a bad mobile connection but every other site I view seems to work just fine. Slashdot, Ars, Hackernews, GMail (the website), Facebook's website (not app), Reddit. Etc.
Any idea how I can debug this? Or is this a known issue?
Here's my code
Router.route('/', {
template: 'front',
});
-
<template name="front">
<header>
<div>
<div class="buttons">
{{> userinfosignin}}
</div>
{{> logo}}
</div>
</header>
<div class="container">
<div class="gallery">
{{> artselection sort="newest" limit="8"}}
{{> artselection sort="popular" limit="8"}}
</div>
</div>
<template name="artselection">
<div class="sortcriteria">
<div class="title">
<div>{{sort}}:</div><div class="right"> see all</div>
</div>
<div class="artgrid">
{{#if Template.subscriptionsReady}}
{{#each art}}
{{> artpiece}}
{{/each}}
{{/if}}
</div>
</div>
</template>
<template name="artpiece">
<div class="artpiece">
<a href="/art/{{_id}}">
<img class="thumbnail" src="{{screenshotLink.url}}" />
</a>
<div class="galleryinfo">
<div class="galleryname">
“{{name}}”
by: {{username}}
</div>
<div>
<a href="/art/{{_id}}">
<span class="views">{{views}}</span><span class="likes">{{likes}}</span>
</a>
</div>
</div>
</div>
</template>
I can see all of that gets rendered except the part inside the {{if Template.subscriptionsReady}}
Here's the code for that template
// in a client section
Template.artselection.onCreated(function() {
var instance = this;
instance.autorun(function() {
var sort = getSortingType(instance.data.sort);
instance.subscribe('artSelection', sort, parseInt(instance.data.limit));
});
});
Template.artselection.helpers({
art: function() {
var instance = Template.instance();
var sortField = getSortingType(instance.data.sort);
var sort = {};
sort[sortField] = -1;
var options = {
sort: sort,
limit: parseInt(instance.data.limit),
};
return Art.find({}, options);
},
});
// in a sever section
Meteor.publish("artSelection", function(sortField, limit) {
var find = {
private: {$ne: true},
};
var sort = {};
sort[sortField] = -1;
var options = {
fields: {settings: false},
sort: sort,
limit: limit,
};
return Art.find(find, options);
});
function getSortingType(sort) {
switch (sort) {
case "mostviewed":
return "views";
case "newest":
return "modifiedAt";
case "popular":
default:
return "likes";
}
}
Note: Art is a collection that's pretty much the same as Posts in any tutorial. The data is small. Just _id, username, owner, title, createdAt, modifiedAt, likes, views, hasSound. That's about it and one field settings which is a string which is at most 2-3k but I'm excluding that field in the publish method. In fact, checking the frames in the Chrome debugger when viewing on desktop it looks like only about 12k of data is sent down over the websocket before the front page is completely rendered. In other words, this isn't an issue of sending lots of data.
I'm on Meteor 1.2.1.
Update
I figured out the issue is actually Chrome's Data Saver feature. I made the bad assumption that since both are WebKit under the hood that remote debugging on Safari would help me find the issue but Chrome is doing fancy networking behind the scenes of it's embedded WebKit view. Turning off the data saver feature and it started working.
According to Google you can disable the data saver feature on the server side by adding the header
Cache-Control: no-transform
So for now I'll try adding that header to my site. Otherwise I'm pretty sure google wants it to just work so I've filed a bug
I am absolutely not sure that it will solve your problem, but have you try the "waitOn" feature of iron router (just to help you to locate the problem) ?
Apparently, you would like to be sure that your subscription to your data has been fully established with this block:
{{#if Template.subscriptionsReady}}
{{#each art}}
{{> artpiece}}
{{/each}}
{{/if}}
Could your try to create a route pointing to your template having the issue, and check if the data are loading on this route ?
Something like the following code and see if the problem persists ?
Router.route('/art_selection', {
name: 'artselection',
waitOn: function () { return Meteor.subscribe('artSelection'); },
data: function () {
return {
art: Art.find(),
}
}
});
If it is working well on the route and not on your main page, then I guess your template is not waiting your subscription to be ready the first time it renders, and do not re-render after the subscription has been completed.

GAS/iOS Mail App: Embedded HTML form's method converted from post to get

First, I'm not positive whether this is an issue with Google Apps Script or the iOS mail app. I've spent a while trying to find anything about the iOS mail app converting embedded html form methods and can't find a single thing.
I am embedding a simple HTML form and sending it via email with Google Apps Script. I'm using post for the form's method and I have a doPost function set up in the script I'm posting back to.
This has been working great for a few months now but I received word from one of my users yesterday that for some reason they were getting a strange error when they tried to submit the form. The user has an iPhone and uses the included Mail app for her email.
I've set up a very simple test script that contains one input and a submit that posts to a simple script to test out the issue. After testing on an iPad, I've found that for whatever reason when I submit with the iOS Mail app, my script returns an error that a doGet function isn't found. I also tested the form using the Gmail iOS app and it calls my doPost method without any issues.
Just to see what happens, I added a doGet function to my script as well and it runs just fine.
Why is the iOS mail app converting my form method from post to get?
Test script that creates the email:
function sendEmail(){
var emailhtml = '<body><form name="iOSemailformtest" action="'+ScriptApp.getService().getUrl()+'" method="post">';
emailhtml += '<input type="radio" name="approval" value="approve">Approve Request<br />';
emailhtml += '<input type="radio" name="approval" value="deny">Deny Request<br />';
emailhtml += '<input type="submit" value="Submit Decision">';
emailhtml += '</form></body>';
MailApp.sendEmail("myemail#email.com", "iOS Email Form Test", "HTML Not Supported?", {htmlBody: emailhtml});
}
If form submission using post isn't reliable, I'd switch to just triggering a function, and not even use a form. Collect the data from the form by getting values out of the fields one by one, or use this.parent to get an object of all the elements in the forms parent element.
var myFieldValue = document.getElementById('idOfInputField').value;
or
<form onsubmit="myFunctionToTrigger(this)">
or
<input onchange="myFunctionToTrigger(this.parent)">

I cannot contact people that have 'Liked' a page that has multiple URL parameters/arguments

Friends,
I am going crazy with this issue, I hope you have the answer for me as I have searched wide for this issue. I have a WEB site that has implemented both the 'Like' button and the 'Comments' button. The issue I'm having is actually two-fold:
First:
The usual 'Admin Page' link that goes beside the 'Like' button once the Admin (me) has liked the page is not always present... I can't figure why, because they are exactly the same PHP pages with different info filled from the DB, but they have identical structure. So I don't understand why:
www.rafaelpolit.com/inicio/index.php?sid=14&gim=10
Shows me the Admin Page link, while
www.rafaelpolit.com/inicio/index.php?sid=14&gim=183
Doesn't.
Any ideas?
Second:
The above problem would not be much of an issue if the procedure described on the Open Graph Protocol page (https://developers.facebook.com/docs/opengraph/#publishing) under Publishing would actually work! Here's the actual problem:
My page uses two parameters in the URL to define the page content: one is the section, the other is the image ID.
My other pages that use a single URL attribute, work fine!!! So, if I access (I am using the graph for simplified purposes):
https://graph.facebook.com/http%3A%2F%2Fwww.rafaelpolit.com%2Finicio%2Findex.php%3Fsid%3D106
It correctly shows:
{
"id": "117419061672096",
"name": "Rafael P\u00f3lit - Macro y Objetos",
"picture": "http://profile.ak.fbcdn.net/hprofile-ak-snc4/188186_117419061672096_2606222_s.jpg",
"link": "http://www.rafaelpolit.com/inicio/index.php?sid=106",
"likes": 2,
"category": "Unknown",
"website": "http://www.rafaelpolit.com/inicio/index.php?sid=106",
"description": "-",
"can_post": true
}
But if I access the graph for one of the URLs with multiple arguments, like:
https://graph.facebook.com/http%3A%2F%2Fwww.rafaelpolit.com%2Finicio%2Findex.php%3Fsid%3D14%26gim%3D10
It truncates the second argument and shows:
{
"id": "http://www.rafaelpolit.com/inicio/index.php?sid=14"
}
As you can see if you enter this though:
graph.facebook.com/159684077425429
The Facebook page is actually correctly working!!! :( Is there a way to actually know a Page_ID if I cannot access the page from any place other than my own site?
So, to sum up my issue:
For some pages I don't get the Admin Page link
For those pages, I have no way of knowing the Page_id
The graph options are not working for pages that have multiple URL arguments/parameters
In the exact same fashion, the https://graph.facebook.com/feed option does not send messages to the people that have 'liked' a page for those pages that have multiple URL parameters, it works fine for those with single parameter.
How do I access the information of a page with two or more parameters?
My final goal is to make something like this actually WORK!:
<?php
$ogurl = urlencode("http://www.rafaelpolit.com/inicio/index.php?sid=14&gim=10");
define("FACEBOOK_APP_ID", "15xxxx84127xxxx");
define("FACEBOOK_SECRET", "xxxx5391830xxxx744b171f0d4b5xxxx");
$mymessage = "Thank you for 'Liking' my Picture.";
$access_token_url = "https://graph.facebook.com/oauth/access_token";
$parameters = "grant_type=client_credentials&client_id=" . FACEBOOK_APP_ID .
"&client_secret=" . FACEBOOK_SECRET;
$access_token = file_get_contents($access_token_url . "?" . $parameters);
$apprequest_url = "https://graph.facebook.com/feed";
$parameters = "?" . $access_token . "&message=" .
urlencode($mymessage) . "&id=" . $ogurl . "&method=post";
$myurl = $apprequest_url . $parameters;
$result = file_get_contents($myurl);
// output the post id
echo "post_id" . $result;
?>
I repeat: This works FINE! if I use the URL of pages with a single URL parameter, it does NOT work if I use URL of pages with multiple parameters.
Any insight? This is a complex issue and I am not a native English speaker, so forgive the extension and any confusion. I appreciate all and every help you may provide!
Thanks a lot,
Rafael Pólit.
ps. Please forgive the non-working links, since I'm new only two of them could actually be links. Most work as copy paste links though, except the graph link which needs https:// in the beginning. Thanks for understanding.
Edit 1:
In response to #Abby 's comment bellow, this is the code I'm using (hopefully formatted instead of the responses in my comments) to insert the button:
<div class="fb_cont ui-corner-all" style="width:706px">
<div id="fb-root"></div>
<script type="text/javascript">
//<![CDATA[
window.fbAsyncInit = function() {
FB.init({appId: '154581841273133', status: true, cookie: true, xfbml: true});
};
(function() {
var e = document.createElement('script'); e.async = true;
e.src = document.location.protocol +
'//connect.facebook.net/en_US/all.js';
document.getElementById('fb-root').appendChild(e);
}());
//]]>
</script>
<div class="fb_cont_int" style="padding:5px;">
<div class="fb_likeDiv" style="width:240px;">
<div class="fb-like" data-href="http://www.rafaelpolit.com/inicio/index.php?sid=14&gim=183" data-send="false" data-width="240" data-show-faces="true" data-colorscheme="dark" data-font="tahoma"></div>
</div>
<div class="fb_commentDiv" style="width:446px;">
<div class="fb-comments" data-href="http://www.rafaelpolit.com/inicio/index.php?sid=14&gim=183" data-num-posts="4" data-width="446" data-colorscheme="dark"></div>
</div>
<div class="dummy"><!-- --></div>
</div>
</div>
Thanks again #Abby for looking into my issue.

Resources