Can't get the data that stored in Redis - javascript

I'm trying to create a user after he verified the code that I send him
so first I generate the code in sendCode resolver and save it in Redis using setex
the problem is that code is set in Redis but when I try to use it in createUser resolver using get it returns null.
const sendCode: MutationResolvers["sendCode"] = async ({
input: { phoneNumber, email },
}: {
input: SendCodeInput;
}) => {
const code = generate4digitNum();
await redis.setex(phoneNumber ?? email, THREE_MINS, code);
return {};
};
const createUser: MutationResolvers["createUser"] = async ({
input: { ...userData },
}: {
input: CreateUserInput;
}) => {
const code = await redis.get(userData.phoneNumber ?? userData.email);
if (code !== userData.code) {
throw new Error(errors[0].id);
}
user = await userModel.create({ ...userData});
return {type: user.type, _id: user._id };
};
the redis.ts file that I create:
const client = redis.createClient({
host: process.env.REDIS_HOST,
password: process.env.REDIS_PASSWORD,
port: Number(process.env.REDIS_PORT),
});
client
.on("connect", function () {
console.log(`connected ${client.connected}`);
})
.on("error", function (error) {
console.log(error);
});
export const get: (key: string) => Promise<string> = promisify(client.get).bind(
client
);
export const setex: (
key: string,
seconds: number,
value: string
) => Promise<string> = promisify(client.setex).bind(client);
I will appreciate any kind of help.
Thanks in advance.

Related

Firesotre error: TypeError: this._delegate.toFirestore is not a function

I'm trying to learn how to use firestore and I can't solve this error when trying to add a client:
(I'm using Next.Js, Typescript and Firebase 8.8.0)
TypeError: this._delegate.toFirestore is not a function
return client;
} else {
const docRef = await this.collection().add(client);
| ^
const doc = await docRef.get();
return doc.data() as Client;
}
I tried to use Firebase V9 but got the same error.
If I add clients collection manually in firebase page I get this error:
TypeError: this._delegate.fromFirestore is not a function
async showAll(): Promise<Client[]> {
const query = await this.collection().get()
return query.docs.map((doc: any) => doc.data()) ?? [];
^
}
My code:
import ClientRepository from "../../core/ClientRepository";
import Client from "../../core/Clients";
import firebase from "../config";
export default class ClientCollection implements ClientRepository {
#converter: any = {
toFireStore(client: Client) {
return {
name: client.name,
taxId: client.taxId,
ie: client.ie,
zipCode: client.zipCode,
state: client.state,
city: client.city,
district: client.district,
street: client.street,
number: client.number,
};
},
fromFireStore(snapshot: firebase.firestore.QueryDocumentSnapshot, options: firebase.firestore.SnapshotOptions): Client {
const data = snapshot.data(options);
return new Client(
data.name,
data.taxId,
data.ie,
data.zipCode,
data.state,
data.city,
data.district,
data.street,
data.number,
snapshot.id
);
},
};
private collection() {
return firebase.firestore().collection("clients").withConverter(this.#converter);
}
async save(client: Client): Promise<Client> {
if (client?.id) {
await this.collection().doc(client.id).set(client);
return client;
} else {
const docRef = await this.collection().add(client);
const doc = await docRef.get();
return doc.data() as Client;
}
}
async delete(client: Client): Promise<void> {
return this.collection().doc(client.id).delete();
}
async showAll(): Promise<Client[]> {
const query = await this.collection().get()
return query.docs.map((doc: any) => doc.data()) ?? [];
}
}

How to initialize App Data in node js and access it without being undefined in jest test?

i am initializing a node js app with crucial data for the app to work from a database in index.js.
index.ts
import {getInitialData} from 'initData.ts';
export let APP_DATA: AppData;
export const initializeAppData = async () => {
try {
APP_DATA = (await getInitialData()) as AppData;
if (process.env.NODE_ENV !== 'test') {
initializeMongoose();
startServer();
}
} catch (error) {
console.log(error);
}
};
initData.ts
let dbName: string = 'initialData';
if (process.env.NODE_ENV === 'test') {
dbName = 'testDb';
}
const uri = `${process.env.MONGODB_URI}/?maxPoolSize=20&w=majority`;
export async function getInitialData() {
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db(dbName);
const configCursor = database
.collection('config')
.find({}, { projection: { _id: 0 } });
const config = await configCursor.toArray();
const aaoCursor = database
.collection('aao')
.find({}, { projection: { _id: 0 } });
const aao = await aaoCursor.toArray();
return { config, aao };
} catch {
(err: Error) => console.log(err);
} finally {
await client.close();
}
}
I'm using this array in another file and import it there.
missionCreateHandler
import { APP_DATA } from '../index';
export const addMissionResources = (
alarmKeyword: AlarmKeyword,
newMission: MissionDocument
) => {
const alarmKeywordObject = APP_DATA?.aao.find(
(el) => Object.keys(el)[0] === alarmKeyword
);
const resourceCommand = Object.values(alarmKeywordObject!);
resourceCommand.forEach((el) => {
Object.entries(el).forEach(([key, value]) => {
for (let ii = 1; ii <= value; ii++) {
newMission.resources?.push({
initialType: key,
status: 'unarranged',
});
}
});
});
};
I'm setting up a mongodb-memory-server in globalSetup.ts for Jest and copy the relevant data to the database from json-files.
globalSetup.ts
export = async function globalSetup() {
const instance = await MongoMemoryServer.create({
instance: { dbName: 'testDb' },
});
const uri = instance.getUri();
(global as any).__MONGOINSTANCE = instance;
process.env.MONGODB_URI = uri.slice(0, uri.lastIndexOf('/'));
process.env.JWT_SECRET = 'testSECRET';
const client = new MongoClient(
`${process.env.MONGODB_URI}/?maxPoolSize=20&w=majority`
);
try {
await client.connect();
const database = client.db('testDb');
database.createCollection('aao');
//#ts-ignore
await database.collection('aao').insertMany(aao['default']);
} catch (error) {
console.log(error);
} finally {
await client.close();
}
};
missionCreateHandler.test.ts
test('it adds the correct mission resources to the array', async () => {
const newMission = await Mission.create({
address: {
street: 'test',
houseNr: 23,
},
alarmKeyword: 'R1',
});
const expected = {
initialType: 'rtw',
status: 'unarranged',
};
addMissionResources('R1', newMission);
expect(newMission.resources[0].initialType).toEqual(expected.initialType);
expect(newMission.resources[0].status).toEqual(expected.status);
});
When runing the test, i get an 'TypeError: Cannot convert undefined or null to object at Function.values ()'. So it seems that the APP_DATA object is not set. I checked that the mongodb-memory-server is set up correctly and feed with the needed data.
When i hardcode the content of APP_DATA in index.ts, the test runs without problems.
So my questions are: How is the best practice to set up initial data in a node js app and where to store it (global object, simple variable and import it in the files where needed)? How can the test successfully run, or is my code just untestable?
Thank you!

Why does my update in a put request overwrite the whole record in Sequelize?

I'm trying to make a "edit" feature for my project, and I'm stuck at this part..
I have a put request :
export const updateEvent = (event, id) => (dispatch, getState) => {
request
.put(`${baseUrl}/event/${id}`)
.send(event)
.then(response => {
dispatch(updatedEvent(response.body))
})
.catch(error => console.log(error))
}
This is the route for the said put, with Sequelize as ORM:
router.put('/event/:id', async (req, res, next) => {
const { id } = req.params
try {
const event = await Event.findByPk(id)
const updatedEvent = await event.update(req.body)
res.send(updatedEvent)
} catch (error) {
next(error)
}
})
When I test it with postman, everything works as expected. Where I ran into my problem is when I'm sending the put data from React in the frontend.
I have a form, and I save my data in the local state, and then dispatch it to actions like this:
handleSubmit = e => {
e.preventDefault()
const id = this.props.event.id
const updatedEvent = {
name: this.state.name,
description: this.state.description,
picture: this.state.picture,
startDate: this.state.startDate,
endDate: this.state.endDate,
userId: this.props.userId
}
this.props.updateEvent(updatedEvent, id)
}
Any value that is left empty in the form is overwriting my fields with nothing (an empty string). How do I properly handle this?
A solution is to filter your object, such that you remove any properties which have empty values and therefore won't be included in the database update.
In your router.put():
router.put('/event/:id', async (req, res, next) => {
const { id } = req.params
try {
const event = await Event.findByPk(id);
// filter req.body to remove empty values
const { body } = req;
const filteredBody = Object.keys(body).reduce((resultObj, key) => {
if(body[key] != ''){
resultObj[key] = body[key];
}
return resultObj;
}, {});
const updatedEvent = await event.update(filteredBody);
res.send(updatedEvent)
} catch (error) {
next(error)
}
})

Firestore Cloud Functions to trigger sms

I have the following cloud function that will trigger a sms message to be sent using Twillio. It works as is but it causes the text message to be sent twice. Is there a way I can modify my function to prevent this? Please note that I am not using the Firebase Realtime Database; I am using the Firebase Firestore Database. This function is being used in conjunction with an Ionic 4 project.
export const textPrayedForNotification = functions.firestore.document('/prayerRequests/{prayerRequestId}').onUpdate(snap => {
const phone: string = snap.after.get('phoneNumber');
const receiveNotifications: boolean = snap.after.get('receiveNotifications');
if (receiveNotifications) {
return client.messages.create({
to: phone,
from: twilioNumber,
body: 'Someone has prayed for you.'
}).then((data: any) => {
console.log(data);
}).catch((error: any) => {
console.log(error);
});
}
});
Update:
Change function to this and now it seems to work.
export const textPrayedForNotification = functions.firestore.document('/prayerRequests/{prayerRequestId}').onUpdate(snap => {
const phone: string = snap.after.get('phoneNumber');
const receiveNotifications: boolean = snap.after.get('receiveNotifications');
const dateLastPrayedBefore = snap.before.get('dateLastPrayed');
const dateLastPrayedAfter = snap.after.get('dateLastPrayed');
if (receiveNotifications) {
if (dateLastPrayedBefore !== dateLastPrayedAfter) {
return client.messages.create({
to: phone,
from: twilioNumber,
body: 'Someone has prayed for you.'
}).then((data: any) => {
console.log(data);
}).catch((error: any) => {
console.log(error);
});
}
}
});

How a guard can be implemented to a graphql resolver

I'm new in graphql and I am trying to integrate an authentication/authorization system in my project. I found an example on Medium, but I do not understand how a guard communicates with a resolver. If someone knows, I will be very grateful.
import { ApolloServer } from 'apollo-server';
import gql from 'graphql-tag';
import { tradeTokenForUser } from './auth-helpers';
const HEADER_NAME = 'authorization';
const typeDefs = gql`
type Query {
me: User
serverTime: String
}
type User {
id: ID!
username: String!
}
`;
const resolvers = {
Query: {
me: authenticated((root, args, context) => context.currentUser),
serverTime: () => new Date(),
},
User: {
id: user => user._id,
username: user => user.username,
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
let authToken = null;
let currentUser = null;
try {
authToken = req.headers[HEADER_NAME];
if (authToken) {
currentUser = await tradeTokenForUser(authToken);
}
} catch (e) {
console.warn(`Unable to authenticate using auth token: ${authToken}`);
}
return {
authToken,
currentUser,
};
},
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
export const authenticated = next => (root, args, context, info) => {
if (!context.currentUser) {
throw new Error(`Unauthenticated!`);
}
return next(root, args, context, info);
};
I do not understand what "next" parameter does and why as an argument when this guard is called I have to return a value?
authenticated is higher-order function that makes the code DRY. next is a callback that is used as a predicate.
It's a DRYer way to write:
...
me: (root, args, context) => {
if (!context.currentUser) {
throw new Error(`Unauthenticated!`);
}
return context.currentUser;
)
...

Categories