How actionssdk cloud functions is working - firebase

index.js file
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {actionssdk} = require('actions-on-google');
const app = actionssdk({debug: true});
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
app.intent('actions.intent.MAIN', function (conv, input) {
conv.ask('<speak>Hi! <break time="1"/> ' +
'You are entering into samplejs5 application by typing ' +
("<say-as >" + input + "</say-as>.</speak>"));
});
const getUser = functions.https.onRequest((req, res) => {
console.log("req.params.uid--------->",req.params.uid)
const uid = req.params.uid;
/*const doc = admin.firestore().doc(`users/${uid}`)
doc.get().then(snapshot => {
res.send(snapshot.data())
}).catch(error => {
res.status(500).send(error)
})*/
})
exports.dairyProduct = functions.https.onRequest(app);
Action.json
{
"actions": [
{
"description": "Default Welcome Intent",
"name": "MAIN",
"fulfillment": {
"conversationName": "testapp"
},
"intent": {
"name": "actions.intent.MAIN",
"trigger": {
"queryPatterns": [
"Talk to Dairy Product"
]
}
}
}
],
"conversations": {
"testapp": {
"name": "testapp",
"url": "https://us-central1-samplejs6-id.cloudfunctions.net/dairyProduct",
"fulfillmentApiVersion": 2,
"inDialogIntents": [
{
"name": "actions.intent.CANCEL"
}
]
}
},
"locale": "en"
}
I am new to actionsdk, I want to get userUID, Since i am using dairyProduct function, how to call getUser? what would be the value of UID,
Please share the guide for creating user, and end user authentication with sample, how they are calling the functions
For calling main intent, we have to type talk to test app, Once main Intent is called, how to authenticate the user

Related

Mocking session and userData with cypress

currently Iam trying to mock a session for website project with cypress, so the tests are not actually accessing database cause Iam using only 0Auth 3th party login (google and github). I already succesfuly mocked a session so main page shows as logged user. However when I click on my profile, it says: No profile (expected behavior when there is no UserInfo data).
This is my cypress code:
Command:
Cypress.Commands.add("login", () => {
cy.intercept("/api/auth/session", { fixture: "session.json" }).as("session");
cy.setCookie("next-auth.session-token", "testcookie");
Cypress.Cookies.preserveOnce("next-auth.session-token");
});
Fixture:
{
"user": {
"name": "test",
"email": "test#test.com",
"slug": "test0000",
"id": "strasnedlouhejstring",
"image": "https://avatars.githubusercontent.com/u/112759319?v=4"
},
"userInfo": {
"bio": "Lorem Testum",
"name": "test",
"email": "test#test.com",
"slug": "test0000",
"id": "strasnedlouhejstring",
"isActive": "true"
},
"expires": "3000-01-01T00:00:00.000Z",
"accessToken": "test"
}
First test (success):
describe("Cypress login", () => {
it("should provide a valid session", () => {
cy.login();
cy.visit("/");
cy.wait("#session");
cy.get("#dropdown > div")
.should("exist")
.then(() => {
cy.log("Cypress login successful");
});
});
});
And finally page rendering:
import ProfilePage from "#components/Layout/ProfilePage";
import { User } from "#prisma/client";
import { getUserInfo } from "#scripts/prisma/getUserInfo";
import { GetServerSideProps } from "next";
import { useSession } from "next-auth/react";
const UserProfile = ({ userInfo }: { userInfo: User | null }) => {
const { data: session } = useSession();
if (userInfo) return <ProfilePage userInfo={userInfo} session={session} />;
return <h1>No profile</h1>;
};
export const getServerSideProps: GetServerSideProps = async (context) => {
const slug = context.query.userProfile?.toString();
if (slug) {
const user = await getUserInfo(slug);
if (user) {
return {
props: { userInfo: JSON.parse(JSON.stringify(user)) },
};
}
}
return {
props: { userInfo: null },
};
};
export default UserProfile;
As I said, the condition is always false so i get the message: No Profile.
I spent 2days figuring this out, however not successfuly.

How to mutation store state in build query redux toolkit

Created an initialState and will be updated the totalPage and currentPage after got the users list.
I found out onQueryStarted from docs, it able to update the store state in this method but only look like only for builder.mutation.
what's the correct way to get the user list and update the store page value in redux toolkit?
Listing two part of the code below:
apiSlice
component to use the hook
// 1. apiSlice
const usersAdapter = createEntityAdapter({})
export const initialState = usersAdapter.getInitialState({
totalPage: 0,
currentPage: 0,
})
export const usersApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getUsers: builder.query({ // <--- the docs are using builder.mutation, but i needed to pass params
query: (args) => {
const { page, limit } = args;
return {
url: `/api/users`,
method: "GET",
params: { page, limit },
}
},
validateStatus: (response, result) => {
return response.status === 200 && !result.isError
},
transformResponse: (responseData) => { // <<-- return { totalPages: 10, currentPage: 1, users: [{}] }
const loadedUsers = responseData?.users.map((user) => user)
return usersAdapter.setAll(initialState, loadedUsers)
},
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled
const {totalPages, currentPage} = data; <----- totalPages & currentPage values are still 0 as initialState
dispatch(setPages({ currentPage, totalPages }))
} catch (error) {
console.error("User Error: ", error)
}
},
providesTags: (result, error, arg) => {
if (result?.ids) {
return [
{ type: "User", id: "LIST" },
...result.ids.map((id) => ({ type: "User", id })),
]
} else return [{ type: "User", id: "LIST" }]
},
})
})
});
export const {
useGetUsersQuery,
} = usersApiSlice
component to use the hook
Try to use the hook in user landing page
const UsersList = () => {
const { data: users, isLoading, isSuccess, isError } = useGetUsersQuery({page: 1, limit: 10 })
return (
<div>return the users data</div>
)
}
update the store value after get the data return

NextJS: New nonce on every application load while enabling CSP

I am trying to implement strict-dynamic CSP rules for my nextjs application. I want a new nonce value at every app load, but it is not happening. Currently a value is set for every build. Since I need the nonce value to set headers for the web pages, I need it in next.config.js.
Please let me know what I'm doing wrong.
next.config.js
const { v4 } = require('uuid');
const { createSecureHeaders } = require("next-secure-headers");
const crypto = require('crypto');
const { PHASE_DEVELOPMENT_SERVER } = require("next/constants");
const generatedNonce = function nonceGenerator() {
const hash = crypto.createHash('sha256');
hash.update(v4());
return hash.digest('base64');
}();
module.exports = function nextConfig(phase, { defaultConfig }) {
return {
publicRuntimeConfig: {
generatedNonce
},
headers: async () => {
return [
{
source: "/(.*)?",
headers: createSecureHeaders({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'none"],
scriptSrc: [
...(phase === PHASE_DEVELOPMENT_SERVER ? ["'unsafe-eval'"] : []),
`'nonce-${generatedNonce}'`,
"'strict-dynamic'",
],
},
},
nosniff: "nosniff",
referrerPolicy: "no-referrer",
frameGuard: "sameorigin",
})
}
]
}
};
}

Does http-proxy-middleware work with Serverless Lambda?

I'm trying to proxy an external API through Serverless Lambda. Trying the following example for the code below: http://localhost:3000/users/1 returns 200 but body is empty. I must be overlooking something as http://localhost:3000/users/11 returns a 404 (as expected).
index.js
'use strict';
const serverless = require('serverless-http');
const express = require('express');
const {
createProxyMiddleware
} = require('http-proxy-middleware');
const app = express();
const jsonPlaceholderProxy = createProxyMiddleware({
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
logLevel: 'debug'
});
app.use('/users', jsonPlaceholderProxy);
app.get('/', (req, res) => {
res.json({
msg: 'Hello from Serverless!'
})
})
const handler = serverless(app);
module.exports.handler = async (event, context) => {
try {
const result = await handler(event, context);
return result;
} catch (error) {
return error;
}
};
serverless.yml
service: sls-proxy-test
provider:
name: aws
runtime: nodejs12.x
plugins:
- serverless-offline
functions:
app:
handler: index.handler
events:
- http:
method: ANY
path: /
- http: "ANY {proxy+}"
package.json
{
"name": "proxy",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"sls": "sls",
"offline": "sls offline start"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "4.17.1",
"http-proxy-middleware": "1.0.1",
"serverless-http": "2.3.2"
},
"devDependencies": {
"serverless": "1.65.0",
"serverless-offline": "5.12.1"
}
}
try to remove the transfer-encoding header from the response in onProxyRes listener inside createProxyMiddleware
const jsonPlaceholderProxy = createProxyMiddleware({
onProxyRes: function (proxyRes, req, res) { // listener on response
delete proxyRes.headers['transfer-encoding']; // remove header from response
},
// remaining code
I had the same issue but adding the below onProxyRes option solved it
onProxyRes(proxyRes, req, res) {
const bodyChunks = [];
proxyRes.on('data', (chunk) => {
bodyChunks.push(chunk);
});
proxyRes.on('end', () => {
const body = Buffer.concat(bodyChunks);
res.status(proxyRes.statusCode);
Object.keys(proxyRes.headers).forEach((key) => {
res.append(key, proxyRes.headers[key]);
});
res.send(body);
res.end();
});
}

Firebase: TypeError: Cannot read property 'getApplicationDefault' of undefined (Cloud ML Engine)

I am new to Firebase, and am testing a Google ML Engine model which I recently deployed. I was trying to follow instructions from this repo: https://github.com/sararob/tswift-detection and was able to deploy the firebase solution as recommended. But when I run the function on Firebase (I upload an image to images folder in Firebase storage), I get an error which states:
Error occurred: TypeError: Cannot read property 'getApplicationDefault' of undefined
at Promise (/user_code/index.js:24:20)
at cmlePredict (/user_code/index.js:23:12)
at file.download.then.then.then (/user_code/index.js:110:20)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Here is the firebase function for reference:
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
'use strict';
const functions = require('firebase-functions');
const gcs = require('#google-cloud/storage');
const admin = require('firebase-admin');
const exec = require('child_process').exec;
const path = require('path');
const fs = require('fs');
const google = require('googleapis');
const sizeOf = require('image-size');
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
function cmlePredict(b64img) {
return new Promise((resolve, reject) => {
google.auth.getApplicationDefault(function (err, authClient) {
if (err) {
reject(err);
}
if (authClient.createScopedRequired && authClient.createScopedRequired()) {
authClient = authClient.createScoped([
'https://www.googleapis.com/auth/cloud-platform'
]);
}
var ml = google.ml({
version: 'v1'
});
const params = {
auth: authClient,
name: 'projects/xx/models/xx',
resource: {
instances: [
{
"inputs": {
"b64": b64img
}
}
]
}
};
ml.projects.predict(params, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
});
}
function resizeImg(filepath) {
return new Promise((resolve, reject) => {
exec(`convert ${filepath} -resize 600x ${filepath}`, (err) => {
if (err) {
console.error('Failed to resize image', err);
reject(err);
} else {
console.log('resized image successfully');
resolve(filepath);
}
});
});
}
exports.runPrediction = functions.storage.object().onChange((event) => {
fs.rmdir('./tmp/', (err) => {
if (err) {
console.log('error deleting tmp/ dir');
}
});
const object = event.data;
const fileBucket = object.bucket;
const filePath = object.name;
const bucket = gcs().bucket(fileBucket);
const fileName = path.basename(filePath);
const file = bucket.file(filePath);
if (filePath.startsWith('images/')) {
const destination = '/tmp/' + fileName;
console.log('got a new image', filePath);
return file.download({
destination: destination
}).then(() => {
if(sizeOf(destination).width > 600) {
console.log('scaling image down...');
return resizeImg(destination);
} else {
return destination;
}
}).then(() => {
console.log('base64 encoding image...');
let bitmap = fs.readFileSync(destination);
return new Buffer(bitmap).toString('base64');
}).then((b64string) => {
console.log('sending image to CMLE...');
return cmlePredict(b64string);
}).then((result) => {
let boxes = result.predictions[0].detection_boxes;
let scores = result.predictions[0].detection_scores;
console.log('got prediction with confidence: ',scores[0]);
// Only output predictions with confidence > 70%
if (scores[0] >= 0.7) {
let dimensions = sizeOf(destination);
let box = boxes[0];
let x0 = box[1] * dimensions.width;
let y0 = box[0] * dimensions.height;
let x1 = box[3] * dimensions.width;
let y1 = box[2] * dimensions.height;
// Draw a box on the image around the predicted bounding box
return new Promise((resolve, reject) => {
console.log(destination);
exec(`convert ${destination} -stroke "#39ff14" -strokewidth 10 -fill none -draw "rectangle ${x0},${y0},${x1},${y1}" ${destination}`, (err) => {
if (err) {
console.error('Failed to draw rect.', err);
reject(err);
} else {
console.log('drew the rect');
bucket.upload(destination, {destination: 'test2.jpg'})
resolve(scores[0]);
}
});
});
} else {
return scores[0];
}
})
.then((confidence) => {
let outlinedImgPath = '';
let imageRef = db.collection('predicted_images').doc(filePath.slice(7));
if (confidence > 0.7) {
outlinedImgPath = `outlined_img/${filePath.slice(7)}`;
imageRef.set({
image_path: outlinedImgPath,
confidence: confidence
});
return bucket.upload(destination, {destination: outlinedImgPath});
} else {
imageRef.set({
image_path: outlinedImgPath,
confidence: confidence
});
console.log('No tswift found');
return confidence;
}
})
.catch(err => {
console.log('Error occurred: ',err);
});
} else {
return 'not a new image';
}
});
These are the libraries I am using:
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"lint": "eslint .",
"serve": "firebase serve --only functions",
"shell": "firebase experimental:functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"dependencies": {
"firebase-admin": "5.8.1",
"firebase-functions": "0.8.1",
"googleapis": "^27.0.0",
"image-size": "^0.6.1",
"#google-cloud/storage": "^1.5.1"
},
"devDependencies": {
"eslint": "^4.12.0",
"eslint-plugin-promise": "^3.6.0"
},
"private": true
}
While deploying, I received this warning:
24:43 warning Unexpected function expression prefer-arrow-callback
I just struggled through this too. I seemed to get it working by using the firebase admin instead:
const credential = admin.credential.applicationDefault();

Resources