Extracting emails from a string containing multiple emails? - reactjs

I have created a component which has email, subject and message input fields. My objective is to add and send email to multiple recipients which is separated by a comma. But it's not working.
In Console, I could see that it is taking multiple recipient into one string like this
"abc#yahoo.com, ert#gmail.com, werty#yahoo.com"
But i want the string to be formatted this way
"abc#yahoo.com", "ert#gmail.com", "werty#yahoo.com"
for example: i want to send an email to 3 recipients:
abc#yahoo.com, ert#gmail.com, werty#yahoo.com
Anyone can help me in this please. Thanks in advance

The problem you intend to solve is that you have a field for email, subject and message which the user enters data to send the email with subject subject and message message to all the emails provided in the field email.
There are a number of ways to solve this problem depending on how you format your user input for the email field. The simplest way would be to accept emails(s) separated by a space. E.g. if user needs to send the email to the 3 emails abc#abc.com, bcd#bcd.com and cde#cde.com then you accept them all in one string where each email is separated by a space.
"abc#abc.com bcd#bcd.com cde#cde.com"
Now you can extract all the emails in your email string by simply calling email.split(" ")
const email = "abc#abc.com bcd#bcd.com cde#cde.com";
const emails = email.split(" ");
console.log(emails);
// ["abc#abc.com","bcd#bcd.com","cde#cde.com"]
So your modified handleSubmit method would be something like this
handleSubmit = e => {
e.preventDefault();
const { email, subject, message } = this.state;
const email_list = email.split(" ");
const data = {
email: email_list,
subject,
message
};
axios
.post(`/api/email`, data, {
headers: { "Content-Type": "application/json" }
})
.then(res => {
console.log(res);
console.log(res.data);
})
.catch(err => {
console.log(err);
});
};
You also need to change your changeHandle method like this
changeHandle = e => this.setState({[e.target.name]: e.target.value });
This is the simplest way to accept multiple emails. You can devise any method you feel works for your app. The method described above is probably the most straightforward way I could think of. Feel free to drop a comment if you need further clarifications

Related

Email validation with zod

I have an email input and i want to validate that the user entered a specific email "abcd#fg.com" and if not to show specific error message "This email is not in our database". I am using zod validation to do that, but how can it be done?
const LoginSchema = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
})
});
I can show how to do this, but I don't think this should be done (more later).
You can use refine to check if the string is exactly some expected value. For example:
const LoginSchema = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine((e) => e === "abcd#fg.com", "This email is not in our database")
});
Then, later if you were going to pull down emails so you can write a validation on the frontend you would use an async refinement with parseAsync like:
const login2 = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine(async (e) => {
const emails = await fetchEmails();
return emails.includes(e);
}, "This email is not in our database")
});
Opinion Warning
I would not recommend doing this for 2 reasons:
The number of emails is likely to be very large if you have any meaningful number of users. Pulling all of those down just to make this check would be a pretty big waste of resources and time.
Security wise, sharing emails of all your users publicly over the API strikes me as a dangerous thing to do. Anyone would hit that API to get real email addresses for all of your users.
I would recommend not validating this as part of the data validation. This validation should happen on the backend and return a 4XX error response when logging in.
Edit
A comment on this post mentioned that you could instead provide an API to validate an email address. This could be safely used from an async refinement and avoids the issues described above.
That would look like:
const login2 = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine(async (e) => {
// Where checkIfEmailIsValid makes a request to the backend
// to see if the email is valid.
return await checkIfEmailIsValid(e);
}, "This email is not in our database")
});

Can URL API endpoint self-correct?

I am using fetch API inside a React application to retrieve and display some quiz questions.
This is my url endpoint: https://opentdb.com/api.php?amount=${amount}&difficulty=${difficulty}&type=multiple
I have noticed that:
-when I misspell part of the URL before "?" then the response doesn't get back.
example:https://opentdb.com/api.ph?amount=${amount}&difficulty=${difficulty}& (missing "p" of php)
-when I misspell part of the url after "?" then, sometimes I get an empty array back, sometimes I get the data back. How can I get data back with a wrong URL?
example: https://opentdb.com/api.php?amoun=${amount}&difficulty=${difficulty}&type=multiple (missing "t" in amount)
I haven't deployed the application yet, I am using vsc and run npm start to develop the application.
Is it possible that the URL auto-corrects? or maybe it gets cached?
my code:
export const fetchQuizQuestions = async (
amount: number,
difficulty: Difficulty
) => {
const endPoint = `https://opentdb.com/api.php?amount=${amount}&difficulty=${difficulty}&type=multiple`;
try {
const response = await fetch(endPoint);
console.log(response);
const data = await response.json();
console.log(data);
if (data.results.length === 0) {
throw new Error("The part after ? contains some mistake");
}
//below I create the new property "all_answers" and make sure the answers order is never the same
return data.results.map((question: Question) => ({
...question,
all_answers: shuffleArray([
...question.incorrect_answers,
question.correct_answer,
]),
}));
} catch (error: any) {
console.log(error.name);
console.log(error.message);
}
};
Before the ? It's the url. So if you make a mistake there, basically it's like sending a letter to a different adress, so you will not get any answers.
After the ? it's the query string. So you're asking for a result, with some parameters (your query)
So if you're saying like "ok, send me back answers with amount = XXX" but you misspell amount, it's just like "ok send me back answers" because you're not asking for amount anymore (but amoun which is nothing for the endpoint)

How to post a message in an existing DM as a Slack Bot

My understanding of the chat.postMessage method of the Slack Web API is that you can, as a bot with a bot token, post messaged to public channels. However, if you want to post to DMs - you would need to request a user token and then post on behalf of the user
However, I've used a few apps that are able to post into DMs as an app (and therefore, I assume, are using a bot token). To me this is ideal, so you're not bugging every person in the Slack workspace to get their user token
Can anyone tell me how this is done?
For reference, here is the code I use to post a message as a bot. It does not work for DMs or for private channels the bot has not been invited to. Would love to fix that. Thanks
function getQueryString(data = {}) {
return Object.entries(data)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&');
}
function postMessageInSlack(bot_token, channelID, userID, message, send_blocks, endpoint) {
const options = {
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
};
const data = {
token: bot_token,
channel: channelID,
text: `${message} from <#${userID}>`,
blocks: JSON.stringify(send_blocks),
}
delete axios.defaults.headers.common["Content-Type"];
axios.post(endpoint,
data, {
options,
transformRequest: getQueryString}
)
.then(res => console.log("result is ", res))
.catch(err => console.log("the error is ", err))
}
You need to open a new conversation with the user, that's if there was none open. To so this you need the conversations.open method. This will return a response that contains the conversation id. You can now use the conversation id in place of the channel id in your chat.postMessage method.

detect the uniqueness of the usernames with Firebase and react js

In a registration form I have three fields
Username
email id
password
When the user registers I need to verify whether the username is already taken or not . I am sending email and password for authentication and updating the profile with username . How can I check the username taken or not ?
firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).then(createdUser => {
console.log(createdUser);
createdUser.user.updateProfile({
username: this.state.username
})
First of all, note that there is no username property for a User. Consequently, passing an object with a username property to the updateProfile() method will not work. You need to pass an object with the displayName and photoURL properties.
If you want to associate a username to your user, what you can very well do (and which is very common) is to have, in the Firestore database, a collection which contains a document for each user. You then store this username value in this document.
Then, to check the "username is not taken", you can query the collection before creating the user, as follows:
var db = firebase.firestore();
var usersRef = db.collection('users');
usersRef.where('username', '==', this.state.username).get()
.then(snapshot => {
if (snapshot.empty) {
return firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password);
} else {
throw new Error('username already taken');
}
})
.then(createdUser => {
console.log(createdUser);
//Create the user doc in the users collection
db.collection('users').doc(createdUser.user.uid).set({username: this.state.username});
})
.catch(err => {
console.log('Error: ', err);
});
Hi you can have a onChange event on username field which calls the api to know if the username already exists or not. And then in onSubmit you can validate if username is not taken you can submit the call.

This email already exists validation

I am making a React application where i submit the username, password and email to the mongo database.
Now I am trying to figure out how I could check inside of React whether the user or email already exists. Meaning so I could show an error-box telling the user to choose something else as an username.
I do know how to do it when I use Node.js and Handlebars. I know how to check my database with the Find() method of mongoose.
But I just don't understand how to think now that I am using React.
When I check if the user already exists in the back-end and it shows that it does exist, how could I inform my front-end (React) that it does?
When I use node.js and handlebars I use flash messages, and it works fine.
I guess my question could be summarized to, how should I do to get my React front-end to cooperate with my Node/Express back-end to share info about a username inside of the database already existing?
I have no code to show, this is more of asking for advice on what tools or methods I should use. I just can't figure it out.
Thank you in advance!
You'll need to have your back-end inform your front-end about whether or not an email has already been used since the front-end has no way of knowing without the back-end.
Basically, when a user tries to register, you should send your registration request from the front-end to the back-end without worrying about duplicate emails. The response from the server should indicate whether or not registration was successful, and if not, why not.
For example the registration component in your React code might look something like this:
class RegistrationComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
error: "",
}
}
handleSubmit = async event => {
event.preventDefault();
const { email, password } = this.state;
const response = await sendRegisterRequest(email, password);
const responseJson = await response.json();
if (response.status !== 200) {
this.setState({error: reponseJson.error});
} else {
// handle successful registration
}
}
render() {
const { error } = this.state;
return (
<form onSubmit={ this.handleSubmit }>
<span>{ error }</span>
{ /* rest of the form */ }
</form>
)
}
}
Where sendRegisterRequest is some module that handles sending registration requests to the server.
Note that this front-end logic expects the server to respond with status 200 on successful registration and with something else (status 400) if there is an error. Also if there is an error, the server should respond with a payload body that looks like: {"error": "That email is already in use"}.
You mention that you know how to check for existing email addresses on the server, so just check in that manner before creating a new account, and if the email address is already in use send the error payload with a status of 400.
You can respond with a 400 status if it occurs then send the error message to the frontend that way. e.g. return res.status(400).json(errors).
catch((err) => {
console.log(err);
if(err.status=404){
alert("email already used");
}

Resources