How to write regex in a sequelize.js field validation.isIn.args - node.js

I had wrote two regex in isIn.args, i want the phone validator can check my input value is one of these, but failed.
var ValidateMe = sequelize.define('Foo', {
phone: {
type: Sequelize.STRING(20),
validate: {
isIn: {
args: [[
// moible number of china
/^(13|14|15|17|18)\d{9}$/i,
// telphone number of china
/^((\(\d{2,3}\))|(\d{3}\-)|(\d{3}))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/i
]],
msg: "moible or telphone number format error!"
}
}
}
})
I want get the result:
var inputNumber = '15208282123'; // or '8008123'
( /^(13|14|15|17|18)\d{9}$/i.test(inputNumber)
|| /^((\(\d{2,3}\))|(\d{3}\-)|(\d{3}))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/i.test(inputNumber)
) === true;
Run it in the browser console, result is true.

sequelize "isIn" validator doesn't provide regex support, it checks weather value is directly present in the list of args or not, instead "is" validator supports regex, but i don't think it will support more than one regex at a time, you need to either convert 2 reg ex into 1 or create custom validator which checks both the regex and return true if one of them is passed, something like below
var ValidateMe = sequelize.define('Foo', {
phone: {
type: Sequelize.STRING(20),
validate: {
validatePhone: function(value) {
if(!/^(13|14|15|17|18)\d{9}$/i.test(value) && !/^((\(\d{2,3}\))|(\d{3}\-)|(\d{3}))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/i.test(value)) {
throw new Error('phone format error!')
}
}
}
}
})

Related

Validate array of objects in Node

I have an array that looks something like this
settings: [
{ key: 'maxImageSize', value: '512' },
{ key: 'maxFileSize', value: '2048' },
{ key: 'searchResultsLimit', value: '10' },
]
I would like to validate the value of each key before saving them to a database.
Example: searchResultsLimit should be greater than 1 but never exceed 20.
I am using Objection.js and express-validator.
Thanks.
Here's a function that returns a boolean based on whether the array is valid or invalid.
function myValidate(settings) {
try {
settings.map((setting) => {
if (validator.toInt(setting.value) <= 1 || validator.toInt(setting.value) >= 20) {
console.log(setting.value);
throw new Error("Invalid");
}
});
} catch (e) {
console.log(e.message);
return false;
}
return true;
}
Turns out validator.js does not provide a validator to check if a number is in range. Check https://github.com/validatorjs/validator.js/issues/330 for details.
In case you want to just ignore the items that are invalid, you can use the filter method instead to get the items in the required range.

How to pass the check empty string with enum in mongoose?

How I can ignore the error like validation failed: gender: "" is not a valid enum value for path gender when receive a empty value to save into database
My schema look like:
Person {
gender: {
type: String,
enum: ['men', 'women'],
required: false
}
}
In my code (NodeJS)
I have a check:
if (body.gender && !['men', 'women'].includes(body.gender.toLowercase())) {
throw Error("Gender invalid");
}
await savePerson(body);
If have to lowerCase value to check in case insensitive
I think in Javascript empty string is not same with null or undefined, so the error is not throw. I don't want to check !isNullOrUndefined(body.gender) as well. But in process save to mongo, error validation failed: gender: "" is not a valid enum value for path gender has been threw by mongoose
The first condition in your if is true when body.gender is not null or undefined or empty string "". So these values pass your validation and go to the .save() function
You can change to this, it will catch the invalid values above :
if (!['men', 'women'].includes(body.gender)) {
throw Error("Gender invalid");
}
console.log(!['men', 'women'].includes(undefined)); // true
console.log(!['men', 'women'].includes(null)); // true
console.log(!['men', 'women'].includes("")); // true
Edit: So, the condition is "the gender is string and is one of "men", "women" case insensitive". I suggest this validation:
if (typeof(body.gender) !== "string" || !['men', 'women'].includes(body.gender.toLowerCase())) {
throw Error("Gender invalid");
}
Below I run some test:
function isValidGender(gender) {
if (typeof(gender) !== "string" || !['men', 'women'].includes(gender.toLowerCase())) {
console.log("Error");
} else {
console.log("Valid");
}
}
isValidGender(undefined);
isValidGender(null);
isValidGender("");
isValidGender("Men");
isValidGender("wOmEn");
isValidGender("AA");

In SuiteScript, can you set the customform field using record.submitFields?

I have a partner record where I would like to change the form if the category field is set to a certain value. However, I can't use this with certain SuiteScript functions because changing the form wipes out any changes that were made to the record. I'm trying to work around this using an afterSubmit function that will use record.SubmitFields to change the form and then redirect.toRecord to reload the page with the change. However, it's not changing the form value. Is there a way to do this with record.submitFields? Am I doing something incorrectly?
var currentRecord = scriptContext.newRecord;
var category = currentRecord.getValue('category');
if(category == '3'){
try{
record.submitFields({
type: record.Type.PARTNER,
id: currentRecord.id,
values: {
'customform': '105'
}
});
log.debug('success');
} catch (e) {
log.error({title: 'error', details: e});
}
}
redirect.toRecord({
type: 'partner',
id: currentRecord.id,
});
}
Yes you can. Whenever you create a url for a record you can generally add a cf parameter that takes the form id. It's the same vaule you'd use if you were setting the field 'customform'. So just skip the submitFields part and do:
redirect.toRecord({
type: 'partner',
id: currentRecord.id,
parameters:{
cf:105
}
});
You can also set the custom form using the submitFields call but that only works for some types of records.
If you need to do this in the beforeLoad here is a fragment in Typescript. The trick to avoid an infinite loop is to check to see if you already have the correct form:
export function beforeLoad(ctx){
let rec : record.Record = ctx.newRecord;
let user = runtime.getCurrentUser();
if(user.roleCenter =='EMPLOYEE'){
if(rec.getValue({fieldId:'assigned'}) != user.id){
throw new Error('You do not have access to this record');
return;
}
}else{
log.debug({
title:'Access for '+ user.entityid,
details:user.roleCenter
});
}
if(ctx.type == ctx.UserEventType.EDIT){
var approvalForm = runtime.getCurrentScript().getParameter({name:'custscript_kotn_approval_form'});
let rec : record.Record = ctx.newRecord;
if( 3 == rec.getValue({fieldId:'custevent_kotn_approval_status'})){
if(approvalForm != rec.getValue({fieldId:'customform'}) && approvalForm != ctx.request.parameters.cf){
redirect.toRecord({
type: <string>rec.type,
id : ''+rec.id,
isEditMode:true,
parameters :{
cf:approvalForm
}
});
return;
}
}
}

#IsPhoneNumber() npm class validator how to add multiple countries code

In Nest js dto I want to validate user mobile number with multiple countries Regex. How can I do this?
#IsPhoneNumber('IN', {
message: (args: ValidationArguments) => {
if (args.value.length !== 10) {
throw new BadRequestException(`${args.value} Wrong Phone Number`);
} else {
throw new InternalServerErrorException();
}
},
})
Different countries has different length of phone numbers. And my suggestion is to keep list of country codes instead of custom regex. It's easier to maintain, and it's more readable. So solution is:
parse phone number
if it's valid check country code
if it's valid pass to next built-in decorator
So I've created my own decorator with libphonenumber-js
Usage in DTO:
export class PhoneDto {
#ToPhone
#IsString({ message: 'must be a valid number' })
readonly phone!: string;
}
Implementation:
import { Transform } from 'class-transformer';
import { parsePhoneNumberFromString } from 'libphonenumber-js';
const validCountries = ['US', 'UK'];
export const ToPhone = Transform(
(value: any) => {
if (typeof value !== 'string') return undefined;
const parsed = parsePhoneNumberFromString(value);
if (!parsed) return undefined;
if (!validCountries.includes(parsed.country)) return undefined;
return parsed.number;
},
{ toClassOnly: true },
);
And yes, this solution adds one more library, it could be slower (actually it depends on your countries list) because of parsing, but as I said before It's more readable and maintainable.
Passing a restricted set of locations to #IsPhoneNumber(region: string) is currently not supported.
Your only chance is to pass "ZZ" as region which will force users to enter numbers with the intl. prefix (see docs)

Optional but non-nullable fields in GraphQL

In an update to our GraphQL API only the models _id field is required hence the ! in the below SDL language code. Other fields such as name don't have to be included on an update but also cannot have null value. Currently, excluding the ! from the name field allows the end user to not have to pass a name in an update but it allows them to pass a null value for the name in, which cannot be allowed.
A null value lets us know that a field needs to be removed from the database.
Below is an example of a model where this would cause a problem - the Name custom scalar doesn't allow null values but GraphQL still allows them through:
type language {
_id: ObjectId
iso: Language_ISO
auto_translate: Boolean
name: Name
updated_at: Date_time
created_at: Date_time
}
input language_create {
iso: Language_ISO!
auto_translate: Boolean
name: Name!
}
input language_update {
_id: ObjectId!
iso: Language_ISO!
auto_translate: Boolean
name: Name
}
When a null value is passed in it bypasses our Scalars so we cannot throw a user input validation error if null isn't an allowed value.
I am aware that ! means non-nullable and that the lack of the ! means the field is nullable however it is frustrating that, as far as I can see, we cannot specify the exact values for a field if a field is not required / optional. This issue only occurs on updates.
Are there any ways to work around this issue through custom Scalars without having to start hardcoding logic into each update resolver which seems cumbersome?
EXAMPLE MUTATION THAT SHOULD FAIL
mutation tests_language_create( $input: language_update! ) { language_update( input: $input ) { name }}
Variables
input: {
_id: "1234",
name: null
}
UPDATE 9/11/18: for reference, I can't find a way around this as there are issues with using custom scalars, custom directives and validation rules. I've opened an issue on GitHub here: https://github.com/apollographql/apollo-server/issues/1942
What you're effectively looking for is custom validation logic. You can add any validation rules you want on top of the "default" set that is normally included when you build a schema. Here's a rough example of how to add a rule that checks for null values on specific types or scalars when they are used as arguments:
const { specifiedRules } = require('graphql/validation')
const { GraphQLError } = require('graphql/error')
const typesToValidate = ['Foo', 'Bar']
// This returns a "Visitor" whose properties get called for
// each node in the document that matches the property's name
function CustomInputFieldsNonNull(context) {
return {
Argument(node) {
const argDef = context.getArgument();
const checkType = typesToValidate.includes(argDef.astNode.type.name.value)
if (checkType && node.value.kind === 'NullValue') {
context.reportError(
new GraphQLError(
`Type ${argDef.astNode.type.name.value} cannot be null`,
node,
),
)
}
},
}
}
// We're going to override the validation rules, so we want to grab
// the existing set of rules and just add on to it
const validationRules = specifiedRules.concat(CustomInputFieldsNonNull)
const server = new ApolloServer({
typeDefs,
resolvers,
validationRules,
})
EDIT: The above only works if you're not using variables, which isn't going to be very helpful in most cases. As a workaround, I was able to utilize a FIELD_DEFINITION directive to achieve the desired behavior. There's probably a number of ways you could approach this, but here's a basic example:
class NonNullInputDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
const { resolve = defaultFieldResolver } = field
const { args: { paths } } = this
field.resolve = async function (...resolverArgs) {
const fieldArgs = resolverArgs[1]
for (const path of paths) {
if (_.get(fieldArgs, path) === null) {
throw new Error(`${path} cannot be null`)
}
}
return resolve.apply(this, resolverArgs)
}
}
}
Then in your schema:
directive #nonNullInput(paths: [String!]!) on FIELD_DEFINITION
input FooInput {
foo: String
bar: String
}
type Query {
foo (input: FooInput!): String #nonNullInput(paths: ["input.foo"])
}
Assuming that the "non null" input fields are the same each time the input is used in the schema, you could map each input's name to an array of field names that should be validated. So you could do something like this as well:
const nonNullFieldMap = {
FooInput: ['foo'],
}
class NonNullInputDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
const { resolve = defaultFieldResolver } = field
const visitedTypeArgs = this.visitedType.args
field.resolve = async function (...resolverArgs) {
const fieldArgs = resolverArgs[1]
visitedTypeArgs.forEach(arg => {
const argType = arg.type.toString().replace("!", "")
const nonNullFields = nonNullFieldMap[argType]
nonNullFields.forEach(nonNullField => {
const path = `${arg.name}.${nonNullField}`
if (_.get(fieldArgs, path) === null) {
throw new Error(`${path} cannot be null`)
}
})
})
return resolve.apply(this, resolverArgs)
}
}
}
And then in your schema:
directive #nonNullInput on FIELD_DEFINITION
type Query {
foo (input: FooInput!): String #nonNullInput
}

Resources