Since it's not possible to use the old way to sign in users any more I tried the new way:
function handleCredentialResponse(response) {
console.log(response);
}
window.onload = function () {
google.accounts.id.initialize({
client_id: googleSignInClientId,
callback: handleCredentialResponse
});
google.accounts.id.renderButton(
document.getElementById("gooDiv"),
{ theme: "outline", size: "large" } // customization attributes
);
// google.accounts.id.prompt(); // also display the One Tap dialog
}
response contains all kind of useless nonsense, I used to get the user ID, profile image and the nickname, how to get those with the new way?
response.credential field is the ID token as a base64 encoded JSON Web Token (JWT) string.
This JWT, and contains the claim set from the authencation server about the user who has signed in to your application. Try and take it and put it in https://jwt.io/ and you will see the claims returend.
function handleCredentialResponse(response) {
console.log("Encoded JWT ID token: " + response.credential);
var tokens = response.credential.split(".");
var payload = JSON.parse(atob(tokens[1]));
console.log(`user id ${payload.sub}`)
console.log(`user name ${payload.name}`)
console.log(`user picture ${payload.picture}`)
}
window.onload = function () {
google.accounts.id.initialize({
client_id: "[REDACTED]",
callback: handleCredentialResponse
});
google.accounts.id.renderButton(
document.getElementById("buttonDiv"),
{ theme: "outline", size: "large" } // customization attributes
);
google.accounts.id.prompt(); // also display the One Tap dialog
}
The JWT is in three parts, header, payload and signature. they are joined by a .
My code splits the jwt by the .
var tokens = response.credential.split(".");
Then parses the payload
var payload = JSON.parse(atob(tokens[1]));
Resulting in
console.log(`user id ${payload.sub}`)
console.log(`user name ${payload.name}`)
console.log(`user picture ${payload.picture}`)
My app sends out email with AWS SES from my node server and all my emails keep ending up in the Promotions Tab of Gmail.
How can I make my emails end up in the Primary Tab in Gmail?
Basically, my email is a simple "confirm your email account" email that is sent to the user after he/she submits registration information on my website. The user will have to click on the link in this email to confirm his email and his account on my website will be created. See below for how I crafted my email on Node.
What I have tried but still I end up in Promotions Tab:
I realize if I put phrases like "click on the link", I end up in Promotions. But even if I replaced that phrase with "open the one-time-use link" like below, I still end up in Promotions.
I avoided fancy html
No pictures
I even replaced noreply#mywebsite.com to somepersonname#mywebsite.com (e.g. jerry#mywebsite.com) it still ends up in Promotions!
I read somewhere to avoid HTML entirely to trick Gmail filters to thinking its written by a human. But how can I do that with aws.ses? Is this the cure?
I am pretty sure many have faced this is an issue. My users keep telling me that they did not receive the confirmation email when in fact it landed in their Promotions Tab. Please help! Any ideas will be much appreciated. Thank you.
// CREATE THE HTML
const html = `
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div >
<p>Hello John!</p>
<p>Please open the one-time-use link below to confirm your email.</p>
<div >
<a href=https://mywebsite.com>Confirm Email</a>
</div>
<p>Not expecting this email? Please disregard this message.</p>
<p>Thank you</p>
</div>
</body>
</html>
`
// CREATE PARAMS FOR SES
const params = {
Destination: {
BccAddresses: [],
CcAddresses: [],
ToAddresses: ["john#gmail.com"],
},
Message: {
Body: {
Html: {
Charset: "UTF-8",
Data: html
},
Text: {
Charset: "UTF-8",
Data: text
}
},
Subject: {
Charset: "UTF-8",
Data: `mywebsite: Confirm New Account k`, // Subject line
}
},
ReplyToAddresses: [],
Source: `"mywebsite" <noreply#mywebsite.com>`, // sender address
}
//SEND OUT EMAIL
ses.sendEmail(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
returnFunc(err); // return END of func fail
} else {
console.log(data); // successful response
returnFunc(null, data); // return END of func success
}
*/
});
I'm new to Javascript and I'm trying to learn express and create an application that will allow users to create new recipes, browse existing recipes, and view recipes.
I've got my server running by typing recipeserver.js in the cmd bar and then typing localhost:3000 in my address bar on google chrome. So far it loads the index.html homepage and from there, I am able to click on a link titled "Create a Recipe" which leads me to the create.html page that looks like this:
create.html page
Initially, there will be only three recipes on the server, which are included in the database object within the recipeserver.js code I've included below. The create.html page allows a user to enter recipe information. When the Save Recipe button is clicked, the addrecipe.js file is supposed to send the recipe data to the server using a POST request to the resource /recipes
Within the server code, all recipes will be stored in a single object called database. The keys of this object will be unique IDs and the values will be the recipes associated with those IDs. I'm stuck on a task where I'm supposed to add a route within the server code to handle POST requests to the /recipes resource. The handler for this route should:
Extract the recipe object included in the POST request body
Generate a unique ID for the new recipe (Etc. a basic integer that increases every time a recipe is added.)
Add a new entry into the recipes object with the key being the unique ID and the value being the recipe object.
When testing my code by adding a few recipes to my server, I should be able to just log the contents of the recipes object to see that it is storing the correct data, like in the picture below (this picture isn't mine):
load recipe in cmd
So as shown in the first picture of my screen, I filled in the contents of the recipe I want to add in create.html. When I click on the "Save Recipe" button however, instead of loading the contents of the recipe into my cmd window, I get the error:
TypeError: C:\Downloads\recipeApplication\views\recipes.pug:8
6| div#main
7| h1 List of Recipes:
> 8| each recipe in recipes
9| a(href="/recipes/" + recipe.id) #{recipe.name}
10| br
11|
Cannot read property 'length' of undefined
I'm a little stumped on how to a route within the server code to handle POST requests to the /recipes resource. I made a function called loadRecipes() that I'm trying to do all this in. I attempted to create a new id and increment it by 1 like the task suggests. I'm having trouble extracting the recipe object included in the POST request body. I attempted this and ended up commenting it out as it created the same error. I'm just trying to get the Save Recipe button to work so that the recipe that is added prints its contents in the cmd bar like in the 2nd picture, but I'm really lost and overwhelmed with the amount of information that comes up when I try to search for a solution and would appreciate some help in getting this to work.
Here's all my code incase anyone wants to run it but I believe my problem just lies in the recipeserver.js file. When the Save Recipe button is clicked, the addrecipe.js file sends the recipe data to the server using a POST request to the resource /recipes.
recipeserver.js:
const express = require('express');
const fs = require("fs");
const shortId = require("short-id");
const session = require('express-session');
const app = express();
const pug = require("pug");
const port = 3000;
let database = {
"0":{
"ingredients":
[
{"name":"Crab","unit":"Tsp","amount":3},
{"name":"Peas","unit":"Cup","amount":12},
{"name":"Basil","unit":"Tbsp","amount":10},
{"name":"Cumin","unit":"Liter","amount":3},
{"name":"Salt","unit":"Tbsp","amount":1}
],
"name":"Boiled Crab with Peas",
"preptime":"13",
"cooktime":"78",
"description":"A boring recipe using Crab and Peas",
"id":"0"
},
"1":{
"ingredients":
[
{"name":"Peanuts","unit":"Liter","amount":10},
{"name":"Artichoke","unit":"Tsp","amount":3},
{"name":"Basil","unit":"Cup","amount":11},
{"name":"Sage","unit":"Grams","amount":13},
{"name":"Pepper","unit":"Cup","amount":1}
],
"name":"Boiled Peanuts with Artichoke",
"preptime":"73",
"cooktime":"74",
"description":"A exciting recipe using Peanuts and Artichoke",
"id":"1"
},
"2":{
"ingredients":
[
{"name":"Lobster","unit":"Tsp","amount":14},
{"name":"Brussel Sprouts","unit":"Liter","amount":14},
{"name":"Sage","unit":"Tbsp","amount":3},
{"name":"Thyme","unit":"Tbsp","amount":12},
{"name":"Pepper","unit":"Tsp","amount":10},
{"name":"Cumin","unit":"Tbsp","amount":11}
],
"name":"Spicy Lobster with Brussel Sprouts",
"preptime":"86",
"cooktime":"19",
"description":"A tasty recipe using Lobster and Brussel Sprouts",
"id":"2"
}
}
let recipes = {};
for (let recipe in database) {
recipes[recipe.id] = recipe;
};
app.set("view engine", "pug");
app.use(express.static("public"));
app.use(express.json());
app.use(express.urlencoded({extended: true}));
app.get("/addrecipe.js", getAddRecipeJS);
app.get("/recipes", loadRecipes);
app.get("/recipe", loadRecipe);
app.route("/recipes", loadRecipes);
app.post("/recipes", loadRecipes);
let id = 1;
function loadRecipes(request, response, next){
response.status(200).render("recipes.pug", {"session": request.session});
/*
console.log("Request received!", request.body);
const newId = shortId.generate();
recipes[newId] = {
id: newId,
type: "recipe",
...request.body,
};
response.sendStatus(201);
*/
id++;
}
function loadRecipe(req, res, next){
res.status(200).render("recipe.pug", {"session": req.session});
}
function getAddRecipeJS(req, res, next){
fs.readFile("addrecipe.js", function(err, data){
if(err){
res.statusCode = 500;
res.end("Error reading file.");
return;
}
res.status(200).send(data);
return;
});
}
app.listen(port);
console.log(`Server listening at http://localhost:${port}`);
index.html:
<html>
<head><title>Recipe App Home Page</title></head>
<body>
<h1>Welcome to the Recipe App</h1>
<br>
Create a Recipe<br>
Browse Recipes<br>
</body>
</html>
create.html:
<html>
<head><title>Create a Recipe</title></head>
<body>
<script src="/js/addrecipe.js"></script>
<button type="button" onclick="genRandom()">Generate Random Recipe Data</button>
<button type="button" onclick="submit()">Save Recipe</button>
<br><br>
Recipe Name: <input type="textbox" id="recipename" size="50"><br>
Prep Time: <input type="textbox" id="preptime" size="50"><br>
Cook Time: <input type="textbox" id="cooktime" size="50"><br>
Description: <textarea rows="5" cols="50" id="description"></textarea><br><br>
Add ingredients:<br>
Unit: <select id="unit">
<option value="Tsp">Teaspoon</option>
<option value="Tbsp">Tbsp</option>
<option value="Cup">Cup</option>
<option value="Liter">Liter</option>
<option value="Gram">Gram</option>
</select><br>
Amount: <input type="textbox" id="amount"><br>
Ingredient: <input type="textbox" id="ingredient"><br>
<button type="button" id="add" onclick="addIngredient()">Add Ingredient</button>
<br><br>
<div id="ingredients">
</div><br>
<button type="button" id="submit" onclick="submit()">Save Recipe</button>
</body>
</html>
addrecipe.js:
let descriptors = ["Sweet", "Spicy", "BBQ", "Braised", "Deconstructed", "Broiled", "Boiled", "Flambeed", "Raw", "Smoked", "Butterflied", "Cured", "Grilled", "Poached"];
let proteins = ["Chicken", "Beef", "Lobster", "Shrimp", "Crab", "Turkey", "Duck", "Tofu", "Chickpeas", "Lentils", "Peanuts", "Kangaroo", "Human", "Goose", "Fish", "Pork", "Eggs", "Deer"];
let accompany = ["Broccoli", "Carrots", "Peas", "Potato", "Kale", "Banana", "Artichoke", "Asparagus", "Beans", "Broccoli", "Brussel Sprouts", "Celery", "Melon", "Mushrooms", "Pumpkin"];
let spices = ["Salt", "Pepper", "Basil", "Thyme", "Sage", "Cumin"];
let mealDescriptors = ["tasty", "mediocre", "very good", "boring", "exciting", "delicious", "easy", "ridiculously complex"];
let units = ["Tbsp", "Tsp", "Cup", "Liter", "Grams"]
let recipe = {ingredients: []};
function addIngredient(){
let name = document.getElementById("ingredient").value;
let amount = document.getElementById("amount").value;
let unit = document.getElementById("unit").value;
let ingredient = {name, amount, unit};
recipe.ingredients.push(ingredient);
updateIngredients();
}
function updateIngredients(){
let innerHTML = "";
recipe.ingredients.forEach(ingredient => {
innerHTML += ingredient.amount + " " + ingredient.unit + " " + ingredient.name + "<br>";
});
document.getElementById("ingredients").innerHTML = innerHTML;
}
function submit(){
recipe.name = document.getElementById("recipename").value;
recipe.preptime = document.getElementById("preptime").value;
recipe.cooktime = document.getElementById("cooktime").value;
recipe.description = document.getElementById("description").value;
let req = new XMLHttpRequest();
req.onreadystatechange = function() {
if(this.readyState==4 && this.status==200){
alert("recipe saved");
}
}
//Send a POST request to the server containing the recipe data
req.open("POST", `/recipes`);
req.setRequestHeader("Content-Type", "application/json");
req.send(JSON.stringify(recipe));
}
recipes.pug:
html
head
title Recipes
body
a(href="/create.html") add a recipe
div#main
h1 List of Recipes:
each recipe in recipes
a(href="/recipes/" + recipe.id) #{recipe.name}
br
recipe.pug:
html
head
title #{recipe.name}
body
div#main
h1 #{recipe.name}
br
First of all, thanks for putting in effort in explaining your issue in detail. One suggestions, you can share the repo instead of snippets of code (since this is quite long, and structure of folder do affects how we can get it up running).
Nonetheless, the error you're getting is due to recipes in recipes.pug is actually undefined.
index.js
function loadRecipes(request, response, next) {
response
.status(200)
// Here, you only pass `session` object to the template engine
// So template engine does not know about `recipes`
// So `recipes` is undefined, and you can't loop it
.render('recipes.pug', { session: request.session});
id++;
}
recipes.pug
html
head
title Recipes
body
a(href="/create.html") add a recipe
div#main
h1 List of Recipes:
// You're having issue here, since `recipes` is not passed to the template
// engine, it will throw an error
each recipe in recipes
a(href="/recipes/" + recipe.id) #{recipe.name}
br
Update your index.js with this
function loadRecipes(request, response, next) {
response
.status(200)
.render('recipes.pug', { session: request.session, recipes: database });
id++;
}
Now, you should be able to view the /recipes page and continue to work on the project.
I note there are quite number of bug in your code.
app.get('/addrecipe.js', getAddRecipeJS);
app.get('/recipes', loadRecipes);
app.get('/recipe', loadRecipe);
app.route('/recipes', loadRecipes);
app.post('/recipes', loadRecipes);
Based on this list of route, you shouldn't be using the same function to handle POST and GET request for /recipes.
GET can be used to retrieve the list of recipes
POST should be used to handle the data submitted, and save it to the database variable inside your index.js
I will give you a simple way of doing this (You should really explore yourself too)
app.post('/recipes', saveRecipes);
function saveRecipes(req, res, next) {
// Data submitted from your page is available in `req.body`
console.log(req.body);
// I'm trying to get a new `key` for the database
// This is because you're using number as `key` for each recipe
// Can skip this and use some random uuid as well
const dbLength = Object.keys(database).length;
// Add this to the database variable, and you're DONE!
database.dbLength = req.body;
res.send('ok');
}
I'm using Direct Line 3.0 and the Microsoft Bot Framework and require the webpage to send some form fields to the bot as if the user sent them. For example when the user presses Submit, the fields email, phone etc are sent to the bot as if the user sent them like this: email, phone, etc.
This is because the bot redirects the user depending on what the values are. The bot is in C# and is hosted on Azure. The logic for submitting the information should be in JavaScript.
Bot is initiated like this:
<div id="chat" style="background-color:white;
width:250px;height:600px;"><div id="bot" />
<script src="https://cdn.botframework.com/botframework-
webchat/latest/botchat.js"></script></div></div>
and through a DirectLine script:
<script>
const botConnection = new BotChat.DirectLine({
secret: 'secret',
});
BotChat.App({
user: { id: 'You' },
bot: { id: 'myId' },
resize: 'detect',
botConnection: botConnection
}, document.getElementById("bot"));
</script>
All I need is to send one string as if the user sent it. I cannot do this with HTML manipulation it seems.
Thanks for anyone pointing me in the right direction!
Sending a message to the bot "like the user would do" is possible using the "Backchannel" functionnality of the webchat.
There is a good sample of use in the Readme file on Github webchat's page: https://github.com/Microsoft/BotFramework-WebChat#the-backchannel.
You have to use your botConnection previously created to send an activity like the following:
botConnection.postActivity({
from: { id: 'me' },
name: 'buttonClicked',
type: 'event',
value: ''
});
Then catch this on your bot code, but checking the Activity type which will be Event in this case.
You can have a look on how they throw this postActivity from a button click in the sample provided: samples here: https://github.com/Microsoft/BotFramework-WebChat/blob/master/samples/backchannel/index.html
Or in this other sample that I made (available on Github, both client web page and bot code): the bot's controller looks like the following:
[BotAuthentication]
public class MessagesController : ApiController
{
/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
// Process each activity
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
// Webchat: getting an "event" activity for our js code
else if (activity.Type == ActivityTypes.Event && activity.ChannelId == "webchat")
{
var receivedEvent = activity.AsEventActivity();
if ("localeSelectionEvent".Equals(receivedEvent.Name, StringComparison.InvariantCultureIgnoreCase))
{
await EchoLocaleAsync(activity, activity.Locale);
}
}
// Sample for Skype: locale is provided in ContactRelationUpdate event
else if (activity.Type == ActivityTypes.ContactRelationUpdate && activity.ChannelId == "skype")
{
await EchoLocaleAsync(activity, activity.Entities[0].Properties["locale"].ToString());
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
private async Task EchoLocaleAsync(Activity activity, string inputLocale)
{
Activity reply = activity.CreateReply($"User locale is {inputLocale}, you should use this language for further treatment");
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
await connector.Conversations.SendToConversationAsync(reply);
}
}
I have an Ionic app and contact form page (with Name, Email, and Phone).
After the user clicks the Submit button, I want this form data to be sent to my E-mail. How do I do this?
You'd need to setup some kind of REST api, so that when the user clicks on the submit button, the data in the contact form is sent to the REST api you've set up, which will trigger it to send an email to you with the contents of the user's message.
Since you've tagged this with Node.JS, I would suggest that you have the contact form's action be send to something like 'http://yoursite.com/sendemail/' and then your API would handle the call with something like:
router.route('/sendemail/')
.post(function(req, res) {
var userInput = req.body;
var message = {
text: userInput.message,
from: userInput.name + ' <' + userInput.email + '>',
to: 'youremail#email.com',
subject: userInput.subject,
attachment:
[
{data: this.text, alternative:true},
]
};
server.send(message, function(err, message) {
if(err) {
res.status(400);
console.log(err);
} else {
res.status(200)
}
});
});
(you'll need to change some variables to fit your code)
Hope this helps!