SvelteKit's breaking change of Jan 19 (see here for details) means that my Google Forms integration is no longer working.
It was a minor struggle to get it working in the first place, and I can't bring this up to date — I repeatedly get the error message, "To access the request body use the text/json/arrayBuffer/formData methods, e.g. body = await request.json()", and a link to the GitHub conversation.
Here's my Contact component...
<script>
let submitStatus;
const submitForm = async (data) => {
submitStatus = 'submitting';
const formData = new FormData(data.currentTarget);
const res = await fetch('contact.json', {
method: 'POST',
body: formData
});
const { message } = await res.json();
submitStatus = message;
};
const refreshForm = () => {
/* Trigger re-render of component */
submitStatus = undefined;
};
</script>
... and here's the corresponding contact.json.js:
export const post = async (request) => {
const name = request.body.get('name');
const email = request.body.get('email');
const message = request.body.get('message');
const res = await fetch(`URL TO RELEVANT GOOGLE FORM GOES HERE`);
if (res.status === 200) {
return {
status: 200,
body: { message: 'success' }
};
} else {
return {
status: 404,
body: { message: 'failed' }
};
}
};
Any help would be greatly appreciated!
The fix is, in fact, relatively simple, and involved only a tiny change to the existing code. I had to access event.request (destructured to request), and proceed from there, prompted by this answer to a similar question. So, after that, contact.json.js looks like...
export const post = async ({ request }) => {
const body = await request.formData();
const name = body.get('name');
const email = body.get('email');
const message = body.get('message');
const response = await fetch(`URL TO RELEVANT GOOGLE FORM GOES HERE`);
if (response.status === 200) {
return {
status: 200,
body: { message: 'success' }
};
} else {
return {
status: 404,
body: { message: 'failed' }
};
}
};
(Note, too, that this whole form was based upon this video by WebJeda, which won't now work with the latest SvelteKit build, but will with this simple alteration.)
Related
I am using the Thunder Client app for VS code to use an API to save the user's data. The API is okay but there is something wrong with my code because I keep getting a 400 "Bad Request" error when I try to send the data to the API. I think the problem might be an array in my code and that is not being sent correctly.
const form = document.querySelector('.form');
const refresh = document.querySelector('.refresh-button');
export const scores = [];
renderScores();
// event listener
form.addEventListener('submit', (e) => {
e.preventDefault();
saveScore();
renderScores();
});
refresh.addEventListener('click', (e) => {
e.preventDefault();
getScores();
renderScores();
});
function renderScores() {
const scoreList = document.querySelector('.result-list');
scoreList.innerHTML = '';
scores.forEach((score) => {
const li = document.createElement('li');
li.innerHTML = `${score.user} : ${score.score}`;
scoreList.appendChild(li);
});
}
async function getScores() {
const savedScores = 'https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/Zl4d7IVkemOTTVg2fUdz/scores/';
const recievedScores = await fetch(savedScores);
const api = await recievedScores.json();
const scores = api.result;
renderScores(scores);
}
async function saveScore() {
const user = document.querySelector('.fullname').value;
const score = document.querySelector('.thescore').value;
const newScore = {
user,
score,
};
scores.push(user, score);
await fetch('https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/Zl4d7IVkemOTTVg2fUdz/scores/', {
method: 'POST',
body: JSON.stringify({
newScore
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
});
getScores();
}
Hey guys I changed my code a little and now I am not getting an error but when I refresh my page I lose all the data
I want to add notifications to an application I've developed.
Unfortunately, Deno has removed the ws package.(https://deno.land/std#0.110.0/ws/mod.ts)
That's why I'm using the websocket inside the denon itself. Since it doesn't have many functions, I have to add some things myself.
For example, sending all messages to open clients.
What I want to do is when the pdf is created, a (data, message) comes from the socket and update the notifications on the page according to the incoming data.
I keep all open clients in a Map. and when the pdf is created, I return this Map and send it to all sockets (data, message).
However, this works for one time.
server conf...
import {
path,
paths,
ctid,
} from "../deps.ts";
const users = new Map();
const sockets = new Map()
const userArr = [];
export const startNotif = (socket,req) => {
const claims = req.get("claims");
const org = req.get("org");
claims.org = org;
console.log("connected")
users.set(claims.sub, {"username":claims.sub,"socket":socket})
users.forEach((user)=>{
if(userArr.length === 0){
userArr.push(user)
}
else if(userArr.every((w)=> w.username !== user.username) )
userArr.push(user)
})
sockets.set(org, userArr)
function broadcastMessage(message) {
sockets.get(org).map((u)=>{
console.log(u.socket.readyState)
u.socket.send(message)
})
}
if (socket.readyState === 3) {
sockets.delete(uid)
return
}
const init = (msg) => {
socket.send(
JSON.stringify({
status: "creating",
})
);
};
const ondata = async (msg) => {
const upfilepath = path.join(paths.work, `CT_${msg.sid}_report.pdf`);
try {
const s=await Deno.readTextFile(upfilepath);
if(s){
socket.send(
JSON.stringify({
status: "end",
})
);
} else {
socket.send(
JSON.stringify({
status: "creating",
})
);
}
} catch(e) {
if(e instanceof Deno.errors.NotFound)
console.error('file does not exists');
}
};
const end = () => {
try {
const endTime = Date.now()
const msg = "Your PDF has been created"
const id = ctid(12) // random id create
broadcastMessage(
JSON.stringify({
id: id,
date: endTime,
status: "done",
message: msg,
read: 'negative',
action: 'pdf'
})
);
} catch (e) {
console.log(400, "Cannot send.", e);
}
}
socket.onmessage = async (e) => {
const cmd = JSON.parse(e.data);
if(cmd.bid === 'start'){
await init(cmd)
}
if(!cmd.bid && cmd.sid){
await ondata(cmd)
}
if(cmd.bid === 'end'){
await end();
}
}
socket.onerror = (e) => {
console.log(e);
};
}
client conf...
export const webSocketHandler = (request) =>
new Promise((res, rej) => {
let url;
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
url = `http://localhost:8080/api/notifications/ws`.replace('http', 'ws');
} else {
url = `${window.location.origin}/api/notifications/ws`.replace('http', 'ws');
}
const token = JSON.parse(sessionStorage.getItem('token'));
const orgname = localStorage.getItem('orgname');
const protocol = `${token}_org_${orgname}`;
const socket = new WebSocket(url, protocol);
const response = Object.create({});
socket.onopen = function () {
socket.send(
JSON.stringify({
bid: 'start',
})
);
};
socket.onmessage = function (event) {
response.data = JSON.parse(event.data);
if (response.data.status === 'creating') {
socket.send(
JSON.stringify({
sid: request.sid,
})
);
} else if (response.data.status === 'end') {
socket.send(
JSON.stringify({
bid: 'end',
})
);
} else if (response.data.status === 'done') {
try {
res(response);
} catch (err) {
rej(err);
}
}
};
socket.onclose = function (event) {
response.state = event.returnValue;
};
socket.onerror = function (error) {
rej(error);
};
});
onclick function of button I use in component...
const donwloadReport = async (type) => {
const query = `?sid=${sid}&reportType=${type}`;
const fileName = `CT_${sid}_report.${type}`;
try {
type === 'pdf' && setLoading(true);
const response = await getScanReportAction(query);
const request = {
sid,
};
webSocketHandler(request)
.then((data) => {
console.log(data);
dispatch({
type: 'update',
data: {
id: data.data.id,
date: data.data.date,
message: data.data.message,
action: data.data.action,
read: data.data.read,
},
});
})
.catch((err) => {
console.log(err);
});
if (type === 'html') {
downloadText(response.data, fileName);
} else {
const blobUrl = await readStream(response.data);
setLoading(false);
downloadURL(blobUrl, fileName);
}
} catch (err) {
displayMessage(err.message);
}
};
Everything works perfectly the first time. When I press the download button for the pdf, the socket works, then a data is returned and I update the notification count with the context I applied according to this data.
Later I realized that this works in a single tab. When I open a new client in the side tab, my notification count does not increase. For this, I wanted to keep all sockets in Map and return them all and send a message to each socket separately. But in this case, when I press the download button for the second time, no data comes from the socket.
Actually, I think that I should do the socket initialization process on the client in the context. When you do this, it starts the socket 2 times in a meaningless way.
In summary, consider an application with organizations and users belonging to those organizations. If the clients of A, B, C users belonging to X organization are open at the same time and user A pressed a pdf download button, I want A, B, C users to be notified when the pdf is downloaded.
I would be very grateful if someone could show me a way around this issue.
Have you looked at the BroadcastChannel API? Maybe that could solve your issue. See for example:
Deno specific: https://medium.com/deno-the-complete-reference/broadcast-channel-in-deno-f76a0b8893f5
Web/Browser API: https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API
executing the fetch code in onNewScanResult multiplt time and hence updating the database accordingly................
initialization of qr scanner.........
this.html5QrcodeScanner = new Html5QrcodeScanner(
qrcodeRegionId,
config,
verbose
); ```Executing scanner when qrcode is scanned```
this.html5QrcodeScanner.render(
this.props.qrCodeSuccessCallback,
this.props.qrCodeErrorCallback
);
}
}
this is main qr code class........
class QrCode extends React.Component {
constructor() {
super();
this.state = {
decodedResults: [],
};
this.onNewScanResult = this.onNewScanResult.bind(this);
}
this is where the executing multiple time is happing.......
onNewScanResult(decodedText, decodedResult) {
`geting data from loacal storage as we saved data earlier in the process about acess level`
const qrRes = decodedText;
const obj = JSON.parse(qrRes);
const token = localStorage.getItem("user");
const userData = JSON.parse(token);
const username = userData[0].userId;
const accesslevel = userData[0].accessLevel;
const result = JSON.parse(qrRes);
const ele = result.ele_name;
const newdata = { ele, username, accesslevel };
const data = {
Element_detail: obj,
accessLevel: newdata.accesslevel,
};
const verifyUser = localStorage.getItem("accessLeveldetails");
const accessdetail = JSON.parse(verifyUser);
```checking is user is verified or not```......
`checking the acess level you can ignore the checking focus on fetch part`....
This particular part is we have to stop executing multiple time so database is only entered with one value
if (accessdetail.accessLevel === data.accessLevel) {
try { ``` this fetch is updating database with multiple entries```
fetch(
data.accessLevel === 20
? `/v0/all_elements_image`
: `/v0/${accessdetail.msg}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(obj),
}
).then((res) => {
console.log(res);
if (!res) {
throw res;
}
return res.json();
});
} catch (error) {
console.log("Error:", error);
}
} else {
alert("WRONG USER");
}
}
}
Here is my first function which listens for a firestore document to be created and then creates a new Google Cloud Task with the appropriate data.
exports.onCreatePost = functions.firestore.document('/posts/{documentId}').onCreate(async (snapshot) => {
const data = snapshot.data()
console.log('data:', data)
const expiresIn = data.expiresIn
console.log('expiresIn:', expiresIn)
//const expiresAt = data.expiresAt
let expirationAtSeconds
if (expiresIn && expiresIn > 0) {
expirationAtSeconds = Date.now() / 1000 + expiresIn
console.log('expirationAtSeconds:', expirationAtSeconds)
}
/*else if (expiresAt) {
expirationAtSeconds = expiresAt.seconds
}*/
if (!expirationAtSeconds) {
// No expiration set on this document
return
}
// Get the project ID from the FIREBASE_CONFIG env var
const project = 'project-name'
const location = 'us-central1'
const queue = 'firestore-ttl'
const tasksClient = new CloudTasksClient()
const queuePath = tasksClient.queuePath(project, location, queue)
const url = `https://${location}-${project}.cloudfunctions.net/firestoreTtlCallback`
const docPath = snapshot.ref.path
const payload = docPath
const body = Buffer.from(JSON.stringify(payload)).toString('base64')
console.log('payload:', payload)
console.log('payload:', body)
const task = {
httpRequest: {
httpMethod: 'POST',
url: url,
body: body,
headers: {
'Content-Type': 'application/json',
}
},
scheduleTime: {
seconds: expirationAtSeconds
}
}
console.log('task:', task)
const [response] = await tasksClient.createTask({ parent: queuePath, task: task})
console.log('task created:', response)
})
Here is the second function which is supposed to delete the document after a certain time. (Time received from the Google Cloud Tasks)
exports.firestoreTtlCallback = functions.https.onRequest(async (req, res) => {
console.log('Delete callback called')
const payload = req.body
console.log('payload', payload)
try {
await admin.firestore().doc(payload.docPath).delete()
res.send(200)
}
catch (error) {
console.error(error)
res.status(500).send(error)
}
})
This is the error I see in the Google Cloud Console after the task calls firestoreTtlCallback
SyntaxError: Unexpected token " in JSON at position 0
at JSON.parse (<anonymous>)
at createStrictSyntaxError (/layers/google.nodejs.functions-framework/functions-framework/node_modules/body-parser/lib/types/json.js:158)
at parse (/layers/google.nodejs.functions-framework/functions-framework/node_modules/body-parser/lib/types/json.js:83)
I am following this example How to schedule a Cloud Function to run in the future with Cloud Tasks
I can't figure out what could be wrong with the JSON. I assume it is something to do with what is inside the http request but I don't seem to see anything wrong. Any help or assistance would be greatly appreciated.
I am trying to implement an API to read if user exists as a member in my mailchimp account and if it is not there then add this member to the list.
I am using #marketing/mailchimp_marketing library as a reference (https://github.com/mailchimp/mailchimp-marketing-node).
The issue: mailchimp is returning 'undefined'. Maybe I am missing something in the code and I am afraid setConfig is not been read (not sure). I really appreciate your support. This is the code used:
const md5 = require('md5');
const mailchimp = require('#mailchimp/mailchimp_marketing');
mailchimp.setConfig({
apiKey: 'my-api-key',
server: 'my-server',
});
const listId = '#listcode';
async function checkstatus(subscriber) { //subscriber is an object received from another js file through
//checkstatus function.
console.log(subscriber); // returns the object ok
const status_id = 'subscribed';
for (let i = 0; i < subscriber.length - 24; i++) {
const no_email = subscriber[i].email.toLowerCase();
const subscriberHash = md5(no_email);
const FNAME_Name = subscriber[i].nome;
const LNAME_Name = subscriber[i].sobrenome;
try {
const response = await mailchimp.lists.getListMember(
listId,
subscriberHash
);
console.log(`${response.status}`); // returns 'undefined'
} catch (e) {
console.error(e.status); // returns 'undefined'
console.log('nao cadastrado');
addmember(no_email, FNAME_Name, LNAME_Name, status_id);
}
}
alert('Done');
}
export { checkstatus };
async function addmember(no_email, FNAME_Name, LNAME_Name, status_id) {
try {
const run = async () => {
const additional = await mailchimp.lists.addListMember(listId, {
email_address: no_email,
status: status_id,
merge_fields: {
FNAME: FNAME_Name,
LNAME: LNAME_Name,
},
});
console.log(
`Successfully added contact as an audience member. The contact's id is ${additional.id}.`
);
};
run();
} catch (e) {
//console.error(e.status);
console.log(e.status);
}
return;
}