mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-13 16:22:59 +10:00
- update to use onCall from firebase functions
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"globals": {
|
"globals": {
|
||||||
|
"atob": true,
|
||||||
"Blob": true,
|
"Blob": true,
|
||||||
"fetch": true,
|
"fetch": true,
|
||||||
"window": true,
|
"window": true,
|
||||||
@ -24,6 +25,7 @@
|
|||||||
"no-param-reassign": 0,
|
"no-param-reassign": 0,
|
||||||
"consistent-return": 0,
|
"consistent-return": 0,
|
||||||
"no-nested-ternary": 0,
|
"no-nested-ternary": 0,
|
||||||
"react/prop-types": 0
|
"react/prop-types": 0,
|
||||||
|
"no-plusplus": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,15 +43,6 @@
|
|||||||
"value": "cache-control: public, max-age=0, must-revalidate"
|
"value": "cache-control: public, max-age=0, must-revalidate"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "page-data/**",
|
|
||||||
"headers": [
|
|
||||||
{
|
|
||||||
"key": "cache-control",
|
|
||||||
"value": "cache-control: public, max-age=0, must-revalidate"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}],
|
}],
|
||||||
|
|||||||
@ -1,26 +1,31 @@
|
|||||||
const functions = require('firebase-functions');
|
const functions = require('firebase-functions');
|
||||||
const puppeteer = require('puppeteer');
|
const puppeteer = require('puppeteer');
|
||||||
const cors = require('cors')({ origin: 'https://rxresume-staging.web.app' });
|
|
||||||
|
|
||||||
const BASE_URL = 'https:/rxresu.me/r/';
|
const BASE_URL = 'https://rxresume-staging.web.app/r/';
|
||||||
|
|
||||||
function timeout(ms) {
|
function timeout(ms) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.printSinglePageResume = functions.https.onRequest((req, res) => {
|
exports.printSinglePageResume = functions.https.onCall(
|
||||||
if (req.method !== 'POST') {
|
async ({ id }, { auth }) => {
|
||||||
return res.status(403).send('Forbidden!');
|
if (!id) {
|
||||||
}
|
throw new functions.https.HttpsError(
|
||||||
|
'invalid-argument',
|
||||||
|
'The function must be called with one arguments "id" containing the resume ID.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!req.query.id) {
|
if (!auth) {
|
||||||
return res.status(400).send('Bad Request!');
|
throw new functions.https.HttpsError(
|
||||||
}
|
'failed-precondition',
|
||||||
|
'The function must be called while authenticated.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch({ headless: true });
|
const browser = await puppeteer.launch({ headless: true });
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
await page.goto(BASE_URL + req.query.id);
|
await page.goto(BASE_URL + id);
|
||||||
await timeout(5000);
|
await timeout(5000);
|
||||||
await page.emulateMediaType('print');
|
await page.emulateMediaType('print');
|
||||||
const height = await page.evaluate(() => {
|
const height = await page.evaluate(() => {
|
||||||
@ -44,48 +49,36 @@ exports.printSinglePageResume = functions.https.onRequest((req, res) => {
|
|||||||
pageRanges: '1',
|
pageRanges: '1',
|
||||||
});
|
});
|
||||||
await browser.close();
|
await browser.close();
|
||||||
return pdf;
|
return Buffer.from(pdf).toString('base64');
|
||||||
}
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return cors(req, res, async () => {
|
exports.printMultiPageResume = functions.https.onCall(
|
||||||
const pdf = await run();
|
async ({ id }, { auth }) => {
|
||||||
res.set({
|
if (!id) {
|
||||||
'Content-Type': 'application/pdf',
|
throw new functions.https.HttpsError(
|
||||||
'Content-Length': pdf.length,
|
'invalid-argument',
|
||||||
});
|
'The function must be called with one arguments "id" containing the resume ID.',
|
||||||
return res.send(pdf);
|
);
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
exports.printMultiPageResume = functions.https.onRequest((req, res) => {
|
if (!auth) {
|
||||||
if (req.method !== 'POST') {
|
throw new functions.https.HttpsError(
|
||||||
return res.status(403).send('Forbidden!');
|
'failed-precondition',
|
||||||
}
|
'The function must be called while authenticated.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!req.query.id) {
|
|
||||||
return res.status(400).send('Bad Request!');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch({ headless: true });
|
const browser = await puppeteer.launch({ headless: true });
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
await page.goto(BASE_URL + req.query.id);
|
await page.goto(BASE_URL + id);
|
||||||
await timeout(5000);
|
await timeout(5000);
|
||||||
await page.emulateMediaType('print');
|
await page.emulateMediaType('print');
|
||||||
const pdf = await page.pdf({
|
const pdf = await page.pdf({
|
||||||
|
format: 'A4',
|
||||||
printBackground: true,
|
printBackground: true,
|
||||||
width: `21cm`,
|
|
||||||
});
|
});
|
||||||
await browser.close();
|
await browser.close();
|
||||||
return pdf;
|
return Buffer.from(pdf).toString('base64');
|
||||||
}
|
},
|
||||||
|
);
|
||||||
return cors(req, res, async () => {
|
|
||||||
const pdf = await run();
|
|
||||||
res.set({
|
|
||||||
'Content-Type': 'application/pdf',
|
|
||||||
'Content-Length': pdf.length,
|
|
||||||
});
|
|
||||||
return res.send(pdf);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
16
functions/package-lock.json
generated
16
functions/package-lock.json
generated
@ -1875,14 +1875,6 @@
|
|||||||
"agent-base": "5",
|
"agent-base": "5",
|
||||||
"debug": "4"
|
"debug": "4"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"rimraf": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
|
||||||
"requires": {
|
|
||||||
"glob": "^7.1.3"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1937,6 +1929,14 @@
|
|||||||
"through2": "^3.0.1"
|
"through2": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'animate.css';
|
|||||||
import 'firebase/analytics';
|
import 'firebase/analytics';
|
||||||
import 'firebase/auth';
|
import 'firebase/auth';
|
||||||
import 'firebase/database';
|
import 'firebase/database';
|
||||||
|
import 'firebase/functions';
|
||||||
import 'firebase/storage';
|
import 'firebase/storage';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { DatabaseProvider } from './src/contexts/DatabaseContext';
|
import { DatabaseProvider } from './src/contexts/DatabaseContext';
|
||||||
@ -11,10 +12,10 @@ import { ResumeProvider } from './src/contexts/ResumeContext';
|
|||||||
import { StorageProvider } from './src/contexts/StorageContext';
|
import { StorageProvider } from './src/contexts/StorageContext';
|
||||||
import { ThemeProvider } from './src/contexts/ThemeContext';
|
import { ThemeProvider } from './src/contexts/ThemeContext';
|
||||||
import { UserProvider } from './src/contexts/UserContext';
|
import { UserProvider } from './src/contexts/UserContext';
|
||||||
|
import './src/styles/global.css';
|
||||||
import './src/styles/shadows.css';
|
import './src/styles/shadows.css';
|
||||||
import './src/styles/tailwind.css';
|
import './src/styles/tailwind.css';
|
||||||
import './src/styles/toastify.css';
|
import './src/styles/toastify.css';
|
||||||
import './src/styles/global.css';
|
|
||||||
|
|
||||||
const theme = createMuiTheme({
|
const theme = createMuiTheme({
|
||||||
typography: {
|
typography: {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'firebase/analytics';
|
import 'firebase/analytics';
|
||||||
import 'firebase/auth';
|
import 'firebase/auth';
|
||||||
import 'firebase/database';
|
import 'firebase/database';
|
||||||
|
import 'firebase/functions';
|
||||||
import 'firebase/storage';
|
import 'firebase/storage';
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
|
import firebase from 'gatsby-plugin-firebase';
|
||||||
import { clone } from 'lodash';
|
import { clone } from 'lodash';
|
||||||
import React, { memo, useContext, useEffect, useState } from 'react';
|
import React, { memo, useContext, useEffect, useState } from 'react';
|
||||||
import { FaPrint } from 'react-icons/fa';
|
import { FaPrint } from 'react-icons/fa';
|
||||||
import Button from '../../components/shared/Button';
|
import Button from '../../components/shared/Button';
|
||||||
import ModalContext from '../../contexts/ModalContext';
|
import ModalContext from '../../contexts/ModalContext';
|
||||||
import { useSelector } from '../../contexts/ResumeContext';
|
import { useSelector } from '../../contexts/ResumeContext';
|
||||||
|
import { b64toBlob } from '../../utils';
|
||||||
import BaseModal from '../BaseModal';
|
import BaseModal from '../BaseModal';
|
||||||
|
|
||||||
const ExportModal = () => {
|
const ExportModal = () => {
|
||||||
@ -11,7 +13,6 @@ const ExportModal = () => {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [isLoadingSingle, setLoadingSingle] = useState(false);
|
const [isLoadingSingle, setLoadingSingle] = useState(false);
|
||||||
const [isLoadingMulti, setLoadingMulti] = useState(false);
|
const [isLoadingMulti, setLoadingMulti] = useState(false);
|
||||||
const functionsUrl = 'https://us-central1-rx-resume.cloudfunctions.net';
|
|
||||||
|
|
||||||
const { emitter, events } = useContext(ModalContext);
|
const { emitter, events } = useContext(ModalContext);
|
||||||
|
|
||||||
@ -37,20 +38,22 @@ const ExportModal = () => {
|
|||||||
|
|
||||||
const handleSinglePageDownload = async () => {
|
const handleSinglePageDownload = async () => {
|
||||||
setLoadingSingle(true);
|
setLoadingSingle(true);
|
||||||
fetch(`${functionsUrl}/printSinglePageResume?id=${state.id}`, {
|
const printSinglePageResume = firebase
|
||||||
method: 'POST',
|
.functions()
|
||||||
})
|
.httpsCallable('printSinglePageResume');
|
||||||
.then((response) => response.blob())
|
const { data } = await printSinglePageResume({ id: state.id });
|
||||||
.then(openFile);
|
const blob = b64toBlob(data, 'application/pdf');
|
||||||
|
openFile(blob);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMultiPageDownload = async () => {
|
const handleMultiPageDownload = async () => {
|
||||||
setLoadingMulti(true);
|
setLoadingMulti(true);
|
||||||
fetch(`${functionsUrl}/printMultiPageResume?id=${state.id}`, {
|
const printMultiPageResume = firebase
|
||||||
method: 'POST',
|
.functions()
|
||||||
})
|
.httpsCallable('printMultiPageResume');
|
||||||
.then((response) => response.blob())
|
const { data } = await printMultiPageResume({ id: state.id });
|
||||||
.then(openFile);
|
const blob = b64toBlob(data, 'application/pdf');
|
||||||
|
openFile(blob);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExportToJson = () => {
|
const handleExportToJson = () => {
|
||||||
|
|||||||
@ -69,3 +69,23 @@ export const move = (
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
|
||||||
|
const byteCharacters = atob(b64Data);
|
||||||
|
const byteArrays = [];
|
||||||
|
|
||||||
|
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
||||||
|
const slice = byteCharacters.slice(offset, offset + sliceSize);
|
||||||
|
|
||||||
|
const byteNumbers = new Array(slice.length);
|
||||||
|
for (let i = 0; i < slice.length; i++) {
|
||||||
|
byteNumbers[i] = slice.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
byteArrays.push(byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob(byteArrays, { type: contentType });
|
||||||
|
return blob;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user