Validation to prevent brand names being in the email field? - javascript

So, I have this list of some brandnames:
const blackListedDomains = [
'facebook',
'google',
'amazon',
'netflix',
'hotmail',
'microsoft',
'gmail',
'yahoo',
]
which I need to prevent users to enter in the email field, what Schema could be built using Yup Package.
For example, I am trying this way:
const DomainSchema = Yup.object().shape({
subdomain: Yup.string()
.required('Required')
.lowercase()
.notOneOf(
blackListedDomains,
'Cannot use trademarked names in domain!',
),
})
But, I don't know how to get it from the email string, for example, if user inputs xyz#google.xyz, then how to extract google from the email string and then iterate it over the domain names list to find if it exists there and then show an error message ?

You can use test function of yup library to create a custom validation rule like this:
const DomainSchema = Yup.object().shape({
email: Yup.string()
.required("Required")
.lowercase()
.email("Not a valid mail")
.test(
"is-not-blacklist",
"Cannot use trademarked names in domain!",
(value) => {
if (value) {
const currentDomain = value.substring(
value.indexOf("#") + 1,
value.indexOf(".")
);
return !blackListedDomains.includes(currentDomain);
}
}
)
});
You can take a look at this sandbox for a live working example of this solution.

Related

sendgrid mail sending error upon placing multiple receiver

I'm using const sgMail = require('#sendgrid/mail'); and utilizing sendgrid version 7.6.2.
When I'm adding two email addresses in array and passing that into send() or sendMultiple() it's throwing me error like this.
status: 'failed',
> Error: Error: String expected for `email`
here's the section where I'm putting the multiple emails,
mailsTo = {
email: ["demo#email.com", "demo1#email.com"],
name: "demo",
type: 'to'
}
here if I pass one email as in form of string the mail is getting triggered. Can anyone please suggest what am I doing wrong.
Thanks in advance
According to the documentation the addresses are to be passed as an array of EmailData (string or object with email and name).
Please try the following:
mailsTo = [
{
email: "demo#email.com",
name: "demo"
},
{
email: "demo1#email.com",
name: "demo"
}
]
Assuming mailsTo is being pass as the to parameter for

How to validate that an object property is required?

I have object types that have a 'translations' property where the fields that can be translated into different languages are passed into the specific 'lang' property as you can see in the schema below.
An English translation is always required and the rest of the languages are optional, I can achieve this by setting .default(undefined) to the optional languages.
When a language is present and the validation for its inner fields fails, the error is always associated to the field itself ('name' in this case). This behaviour is expected.
What I else want to achieve and I don't know how is to show an error when the 'translations' property 'en' is not present with a message like 'An English translation is required'.
const categoryTranslationsSchema = object({
name: string()
.min(3, 'Must have at least 3 characters.')
.max(16, 'Cannot be longer than 16 characteres.')
.required('Must provide a name.')
})
const categorySchema = object({
slug: string()
.min(3, 'Must have at least 3 characters.')
.max(16, 'Cannot be longer than 16 characteres.')
.lowercase()
.trim()
.matches(/^(?![0-9-]+$)(?:[a-z]{2,}-?|[0-9]-?)+(?<!-)$/gm, 'Must start with a letter and can'
+ ' only contain letters, numbers or dashes (no more than one consecutive).')
.required('The slug is required.'),
translations: object({
en: categoryTranslationsSchema,
es: categoryTranslationsSchema
.default(undefined),
de: categoryTranslationsSchema
.default(undefined)
})
})
I think you should look into using a custom locale dictionary. Which allows you to customize the default messages used by Yup, when no message is provided with a validation test. If any message is missing in the custom dictionary the error message will default to Yup's one. It also provided enables multi-language support.
https://github.com/jquense/yup#using-a-custom-locale-dictionary
import { setLocale } from 'yup';
setLocale({
mixed: {
default: 'Não é válido',
},
number: {
min: 'Deve ser maior que ${min}',
},
});
// now use Yup schemas AFTER you defined your custom dictionary
let schema = yup.object().shape({
name: yup.string(),
age: yup.number().min(18),
});
schema.validate({ name: 'jimmy', age: 11 }).catch(function (err) {
err.name; // => 'ValidationError'
err.errors; // => ['Deve ser maior que 18']
});
If you can't get what you're looking for with just that try combining it with yup.lazy which creates a schema that is evaluated at validation/cast time. This can be nested inside your object schema as well. https://github.com/jquense/yup#yuplazyvalue-any--schema-lazy
here is an idea of what you can do:
translations: Yup.lazy(value => {
switch (typeof value) {
case 'object':
return Yup.object(); // schema for object
case 'string':
return Yup.string().min(MIN_DESC_LENGTH).max(_MAX_NAME_LENGTH); // schema for string
default:
return Yup.mixed(); // here you can decide what is the default
}
})
Well, the problem when validating nested object is that they default to empty objects {}, for that reason it passes the validation and enters the inner validation.
The solution is then making all objects .default(undefined) that way we can add more requirements to the object validation itself, in this case making it required.
So the solution was as simple as that:
const categorySchema = object({
slug: string()
.min(3, 'Must have at least 3 characters.')
.max(16, 'Cannot be longer than 16 characteres.')
.lowercase()
.trim()
.matches(/^(?![0-9-]+$)(?:[a-z]{2,}-?|[0-9]-?)+(?<!-)$/gm, 'Must start with a letter and can'
+ ' only contain letters, numbers or dashes (no more than one consecutive).')
.required('The slug is required.'),
translations: object({
en: categoryTranslationsSchema
.default(undefined)
.required('An English translation must be provided.'),
zh: categoryTranslationsSchema
.default(undefined)
}).default(undefined)
.required('Translations must be defined.'),
})

React Yup schema

I'm using Yup to validate an email field:
const Schema = Yup.object().shape({
email: Yup.string()
.email("non valid email format")
.required("Email required"),
...
During form submit, I check if the email domain is included in a list of forbidden domains, if yes, I display an error message in a popup:
const forbidDomains = domains;
const domain = data.email.split("#");
if(forbidDomains.Domains.includes(domain[1])) {
this.setState({openPopup:true,statusMessage:"domain not allowed : " + domain[1]})
this.setState({isSubmitting:false})
return;
}
I would like to check the domain in the Yup schema, but I'm not sure if it's possible.
I think that what you are looking for is the .test() from Yup. Maybe something like this may work:
const schema = {
email: Yup.string()
.string()
.email()
.test('test-name', 'Validation failure message',
function(value) {
// your logic to check the domain
})
}

Access to required fields with Yup

I use react-hook-form with yup to validate my forms.
I want to know all required fields of a schema to display some information in form (like '*' for required fields).
We could achieve this with this line of code :
schema.describe().fields[field].tests.findIndex(({ name }) => name === 'required'
However, this code doesn't work for conditional validation.
Schema example :
const schema = yup.object().shape({
email: yup
.string()
.email()
.required(),
isProfileRequired: yup
.boolean(),
profile: yup
.object()
.when('isProfileRequired',{
is: (isProfileRequired) => isProfileRequired,
then:
yup
.object()
.nullable()
.required()
})
})
Is there a way to retrieve this informations within the form ?
There is actually no "nice" way to do it but this works:
function isRequired(field){
return schema.fields[field]._exclusive.required || false
}
Notice: schema.fields[field]._exclusive.required returns true if required or undefined.
Testing exclusiveTests instead of _exclusive worked for me.
const isRequired =
validationSchema?.fields[aField.name]?.exclusiveTests?.required || false;

Password confirmation and password are equal but validation is still triggering JOI in React component

I creating a register form and the problems accurs while try validating password confirmation. I am using the last version of JOI-Browser.
I tried the code below and the validation error was triggered even though password and password confirmation have the same values.
password: Joi.string()
.min(5)
.required(),
passwordConfirmation: Joi.ref("password")
Here is my state object:
password: "12345"
passwordConfirmation: "12345"
username: ""
errors: {…}
passwordConfirmation: "\"passwordConfirmation\" must be one of [ref:password]"
I passed several hours trying several approaches and reading the documentation, but still no luck, the validation is still triggering,
I have other validations in this form and they work fine.
I don't think Joi.ref should be used that way.
I usually tend to do this way:
const passwordConfirmation = Joi.string()
.required()
.valid(Joi.ref('password'))
.options({
language: {
any: {
allowOnly: '!!Passwords do not match',
}
}
})
If you refer to the docs, you will see:
Note that references can only be used where explicitly supported such as in valid() or invalid() rules. If upwards (parents) references are needed, use object.assert().
If anyone has encountered a similar problem, this is the solution I have used:
validateProperty = (input) => {
let obj = { [input.name]: input.value };
let schema = { [input.name]: this.schema[input.name] };
if (input.name.endsWith("_confirm")) {
const dependentInput = input.name.substring(
0,
input.name.indexOf("_confirm")
);
obj[dependentInput] = this.state.data[dependentInput];
schema[dependentInput] = this.schema[dependentInput];
}
const { error } = Joi.validate(obj, schema);
return error ? error.details[0].message : null;
};
In my case, I have looked for _confirm because I have the field names as password and password_confirm. You need to make changes here as per your requirements.
Main logic, you just need to add value and schema of password when you are validating password_confirm
I find out what was happening. My code above was right, the problem was in my validate function.
Gabriele's Petrioli comment help me out. this is the function that cause me problems:
validateProperty = ({ name: propertyName, value }) => {
const obj = { [propertyName]: value };
const schema = { [propertyName]: this.schema[propertyName] };
const { error } = Joi.validate(obj, schema);
return error ? error.details[0].message : null;};
Has you can see i tried validate each property individually, so i can make the form more dynamic.
This trigger the validation error because when i try to validate confirmPassword there was no value in password because i passed only the value the correspond to confirmaPassword, it also needed the password value to make the comparison.
Rookie mistake

Categories