import { ConnectionEventStatuses , EventTypes , MessageEventAck , MessageEventFrom , MessageEventTypes , } from '@botonic/core' ; import { Request } from 'express' ; import { body , checkSchema , ParamSchema , Result , Schema , validationResult , } from 'express-validator' ; import { equals , getOptionalSchema , inBody , inParams , isBoolean , isDateTime , isIn , isNaturalNumber , isNumeric , isOptional , isRequired , toInt , } from './common' ; export const eventIdParamSchema = { ... inParams , ... isRequired } ; export const buttonsSchema = { buttons : { ... inBody , ... isOptional , isArray : true , errorMessage : 'buttons have to be an array' , } , 'buttons.*.title' : { ... inBody , ... isRequired } , 'buttons.*.webview' : { ... inBody , ... isOptional } , 'buttons.*.params' : { ... inBody , ... isOptional } , 'buttons.*.url' : { ... inBody , ... isOptional } , 'buttons.*.target' : { ... inBody , ... isOptional } , 'buttons.*.payload' : { ... inBody , ... isOptional } , } ; export const repliesSchema = { replies : { ... inBody , ... isOptional , isArray : true , errorMessage : 'replies have to be an array' , } , 'replies.*.title' : { ... inBody , ... isRequired } , 'replies.*.payload' : { ... inBody , ... isRequired } , } ; export const carouselSchema = { elements : { ... inBody , isArray : true , errorMessage : 'elements have to be an array' , } , 'elements.*.pic' : { ... inBody , ... isRequired } , 'elements.*.title' : { ... inBody , ... isRequired } , 'elements.*.subtitle' : { ... inBody , ... isOptional } , } ; export const baseEventSchema = { eventId : { ... inBody , ... isRequired } , eventType : { ... inBody , ... isRequired , ... isIn ( Object . values ( EventTypes ) ) } , createdAt : { ... inBody , ... isRequired , ... isDateTime } , modifiedAt : { ... inBody , ... isOptional , ... isDateTime } , } ; export const botonicMessageEventSchema = { ... baseEventSchema , ack : { ... inBody , ... isRequired , ... isIn ( Object . values ( MessageEventAck ) ) } , from : { ... inBody , ... isRequired , ... isIn ( Object . values ( MessageEventFrom ) ) } , type : { ... inBody , ... isRequired , ... isIn ( Object . values ( MessageEventTypes ) ) } , typing : { ... inBody , ... isOptional , ... isNaturalNumber , ... toInt } , delay : { ... inBody , ... isOptional , ... isNaturalNumber , ... toInt } , } ; export const mediaMessageEventSchema = { ... botonicMessageEventSchema , ... buttonsSchema , src : { ... inBody , ... isRequired } , } ; export const textMessageEventSchema = { ... botonicMessageEventSchema , ... buttonsSchema , ... repliesSchema , type : { ... inBody , ... isRequired , ... equals ( MessageEventTypes . TEXT ) , } , markdown : { ... inBody , ... isRequired , ... isBoolean } , text : { ... inBody , ... isRequired } , } ; export const postbackMessageEventSchema = { ... botonicMessageEventSchema , payload : { ... inBody , ... isRequired } , } ; export const audioMessageEventSchema = { ... mediaMessageEventSchema , type : { ... inBody , ... isRequired , ... equals ( MessageEventTypes . AUDIO ) } , } ; export const imageMessageEventSchema = { ... mediaMessageEventSchema , type : { ... inBody , ... isRequired , ... equals ( MessageEventTypes . IMAGE ) } , } ; export const documentMessageEventSchema = { ... mediaMessageEventSchema , type : { ... inBody , ... isRequired , ... equals ( MessageEventTypes . DOCUMENT ) } , } ; export const videoMessageEventSchema = { ... mediaMessageEventSchema , type : { ... inBody , ... isRequired , ... equals ( MessageEventTypes . VIDEO ) } , } ; export const locationMessageEventSchema = { ... botonicMessageEventSchema , type : { ... inBody , ... isRequired , ... equals ( MessageEventTypes . LOCATION ) } , lat : { ... inBody , ... isRequired , ... isNumeric , ... toInt } , long : { ... inBody , ... isRequired , ... isNumeric , ... toInt } , } ; export const carouselMessageEventSchema = { ... botonicMessageEventSchema , ... carouselSchema , type : { ... inBody , ... isRequired , ... equals ( MessageEventTypes . CAROUSEL ) } , } ; export const customMessageEventSchema = { ... botonicMessageEventSchema , ... repliesSchema , type : { ... inBody , ... isRequired , ... equals ( MessageEventTypes . CUSTOM ) } , customTypeName : { ... inBody , ... isRequired } , } ; export const connectionEventSchema = { ... baseEventSchema , eventType : { ... inBody , ... isRequired , ... equals ( EventTypes . CONNECTION ) } , status : { ... inBody , ... isRequired , ... isIn ( Object . values ( ConnectionEventStatuses ) ) , } , } ; export const botonicEventValidationChains = [ checkSchema ( textMessageEventSchema ) , checkSchema ( postbackMessageEventSchema ) , checkSchema ( audioMessageEventSchema ) , checkSchema ( documentMessageEventSchema ) , checkSchema ( imageMessageEventSchema ) , checkSchema ( videoMessageEventSchema ) , checkSchema ( locationMessageEventSchema ) , checkSchema ( carouselMessageEventSchema ) , checkSchema ( customMessageEventSchema ) , checkSchema ( connectionEventSchema ) , ] ; export async function validateBotonicEventData ( { request , allFieldsOptional = false , withParamEventId = false , } ) { const opt = allFieldsOptional ; const e = withParamEventId ; await checkSchema ( getSchema ( baseEventSchema , opt , e ) ) . run ( request ) ; const errors = validationResult ( request ) ; if ( ! errors . isEmpty ( ) ) { return errors ; } let schema ; if ( request . body . eventType === EventTypes . CONNECTION ) { schema = getSchema ( connectionEventSchema , opt , e ) ; } else { switch ( request . body . type ) { case MessageEventTypes . TEXT : schema = getSchema ( textMessageEventSchema , opt , e ) ; break ; case MessageEventTypes . POSTBACK : schema = getSchema ( postbackMessageEventSchema , opt , e ) ; break ; case MessageEventTypes . AUDIO : schema = getSchema ( audioMessageEventSchema , opt , e ) ; break ; case MessageEventTypes . DOCUMENT : schema = getSchema ( documentMessageEventSchema , opt , e ) ; break ; case MessageEventTypes . IMAGE : schema = getSchema ( imageMessageEventSchema , opt , e ) ; break ; case MessageEventTypes . VIDEO : schema = getSchema ( videoMessageEventSchema , opt , e ) ; break ; case MessageEventTypes . LOCATION : schema = getSchema ( locationMessageEventSchema , opt , e ) ; break ; case MessageEventTypes . CAROUSEL : schema = getSchema ( carouselMessageEventSchema , opt , e ) ; break ; case MessageEventTypes . CUSTOM : schema = getSchema ( customMessageEventSchema , opt , e ) ; break ; default : schema = getSchema ( botonicMessageEventSchema , opt , e ) ; break ; } } await checkSchema ( schema ) . run ( request ) ; return validationResult ( request ) ; } export async function validateEventType ( req ) { await body ( 'eventType' ) . equals ( EventTypes . CONNECTION ) . run ( req ) ; return validationResult ( req ) ; } export async function validateType ( req ) { const messageEventTypes = Object . values ( MessageEventTypes ) ; await body ( 'type' ) . isIn ( messageEventTypes ) . withMessage ( `Invalid value. Allowed values: ${ messageEventTypes }` ) . run ( req ) ; return validationResult ( req ) ; } function getSchema ( schema , allFieldsOptional = false , withParamEventId = false ) { if ( withParamEventId ) { schema = { ... schema , eventId : eventIdParamSchema } ; } if ( allFieldsOptional ) { schema = getOptionalSchema ( schema ) ; } return schema ; }