I want to validate a discord embed before sending it.
Which means, I want to know if an embed has nothing wrong with it before actually sending it on a channel.
var embed = {
title: 'some title',
description: 'some description',
color: 'foo bar'
}
// embed.color is not a valid color, so it will trigger an error when I send it.
// Here I want some way to know that there's something wrong with the embed object.
message.channel.send({embed});
I have made a function to validate embeds. However, it's incomplete and may have false positives or false negatives, but it should meet your needs.
function validURL(url) {
try {
new URL(url);
} catch (err) {
return false;
}
return true;
}
function validEmbed(embed) {
return Object.entries({
title: (title) => typeof title === 'string',
description: (description) => typeof description === 'string',
url: (url) => validURL(url),
timestamp: (timestamp) => (new Date(timestamp)).getTime() > 0,
color: (color) => typeof color === 'number',
fields: (fields) => fields.every(field => typeof field.name === 'string' && typeof field.value === 'string' && typeof field.inline === 'boolean'),
thumbnail: (thumbnail) => validURL(thumbnail.url),
image: (image) => validURL(image.url),
author: (author) => typeof author.name === 'string' && validURL(author.url) && validURL(author.icon_url),
footer: (footer) => typeof footer.text === 'string' && validURL(footer.icon_url)
}).every(field => {
if (!(field[0] in embed)) return true;
return embed[field[0]] && field[1](embed[field[0]]);
});
}
Here is an exaple snippet:
function validURL(e){try{new URL(e)}catch(e){return!1}return!0}function validEmbed(e){return Object.entries({title:e=>"string"==typeof e,description:e=>"string"==typeof e,url:e=>validURL(e),timestamp:e=>new Date(e).getTime()>0,color:e=>"number"==typeof e,fields:e=>e.every(e=>"string"==typeof e.name&&"string"==typeof e.value&&"boolean"==typeof e.inline),thumbnail:e=>validURL(e.url),image:e=>validURL(e.url),author:e=>"string"==typeof e.name&&validURL(e.url)&&validURL(e.icon_url),footer:e=>"string"==typeof e.text&&validURL(e.icon_url)}).every(t=>!(t[0]in e)||e[t[0]]&&t[1](e[t[0]]))}
/* returns true */
console.log(validEmbed({
title: 'The title'
}));
/* returns true */
console.log(validEmbed({
title: 'The title',
description: 'Sample Description.',
url: 'https://i.imgur.com/ttHwmCl.jpg',
timestamp: '2020-07-30T14:44:05.876Z',
color: 3447003,
fields: [{
name: 'name',
value: 'value',
inline: false
},
{
name: 'name2',
value: 'value2',
inline: true
}
],
thumbnail: {
url: 'attachment://stackoverflow2.jpg'
},
image: {
url: 'attachment://stackoverflow.jpg'
},
author: {
name: 'Daemon Beast',
url: 'https://i.imgur.com/P4L260P.jpg',
icon_url: 'https://i.imgur.com/P4L260P.jpg'
},
footer: {
text: 'footer text',
icon_url: 'https://i.imgur.com/ttHwmCl.jpg'
}
}));
/* returns false */
console.log(validEmbed({
author: 4567876567
}));
Related
I'm pretty new to the headless cms of sanity.io. As I'm trying to fetch my data im getting this error but couldn't figure out why or where the problem could be exactly.
Anybody some ideas?
Error: Error serializing .images returned from getServerSideProps in "/company/[slug]".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
//the slug file
export const Company = ({ title, slug, logo, images, currency, categories, body, url, location }) => {
console.log(title, slug, logo, images, currency, categories, body, url, location )
return <>Content</>
};
export const getServerSideProps = async pageContext => {
const pageSlug = pageContext.query.slug;
if (!pageSlug) {
return {
notFound: true
}
}
const query = encodeURIComponent(`*[ _type == "company" && slug.current == "${pageSlug}" ]`);
const url = `https://op5ktqwm.api.sanity.io/v1/data/query/production?query=${query}`;
const result = await fetch(url).then(res => res.json());
const post = result.result[0];
if (!post) {
return {
notFound: true
}
} else {
return {
props: {
title: post.title,
slug: post.slug,
logo: post.logo,
images: post.images,
currency: post.currency,
categories: post.categories,
body: post.body,
url: post.url,
location: post.location
}
}
}
}
export default Company;
//backend code structure
export default {
name: 'company',
title: 'Company',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96,
},
},
{
name: 'logo',
title: 'Logo',
type: 'image',
},
{
name: 'images',
title: 'Images',
type: 'array',
of: [{type: 'companyImage'}]
},
{
name: 'currency',
title: 'Currency',
type: 'array',
of: [
{
type: 'reference',
to: {type: 'currency'},
},
],
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [
{
type: 'reference',
to: {type: 'category'},
},
],
},
{
name: 'body',
title: 'Body',
type: 'localeBlockContent',
},
{
name: 'url',
title: 'URL',
type: 'string',
},
{
name: 'location',
title: 'Location',
type: 'geopoint',
},
],
preview: {
select: {
title: 'title',
manufactor: 'manufactor.title',
media: 'defaultProductVariant.images[0]',
},
},
}
I have the following array. I am using this array to dynamically produce checkboxes on my UI. This is being used to save user config as to what they will be able to see in a nav menu.
accessLevels: any = [
{
description: "Properties",
type: '1',
selected: false
},
{
description: "Equipment",
type: '2',
selected: false
},
{
description: "Jobs",
type: '3',
selected: false
},
{
description: "Calender",
type: '4',
selected: false
}
]
I am making a call to an API which returns me an array of the users config. So what I will get is an array of the pages and their type like this:
{
description: "Equipment",
type: '2'
},
{
description: "Jobs",
type: '3'
}
In the array returned from the API I am just getting the values that should appear checked on the check boxes so what I want to do is loop through the returned array and check if any of the types match any types in the checkbox array if they do I want to set 'selected' to true. Thus checking the checkbox.
Here is what I have so far:
async loadLandlordConfig(key: string) {
const result = await this.userService.loadLandlordConfig(key);
//let accessLevels = [];
this.selectedApiValues = result[0].accessLevels;
this.selectedApiValues.forEach((selectedValue)=> {
});
}
Im not sure how to cross check the values and then change selected to true.
Hope I have made everything clear enough.
Any questions please ask. All help appreciated.
const accessLevels: any[] = [
{
description: 'Properties',
type: '1',
selected: false
},
{
description: 'Equipment',
type: '2',
selected: false
},
{
description: 'Jobs',
type: '3',
selected: false
},
{
description: 'Calender',
type: '4',
selected: false
}];
const results: any[] = [
{
description: 'Equipment',
type: '2'
},
{
description: 'Jobs',
type: '3'
}];
accessLevels.forEach(accessLevel => {
accessLevel.selected = results.some(x => x.type === accessLevel.type); });
For small arrays
You can check for the existence within a filter using some:
const intersect = this.array1.filter(a1 =>
this.array2.some(a2 => a1.type === a2.type));
The problem with this is that you are doing multiple loops through array 2.
For larger arrays
To keep your loops to a constant number, you could create a map of one of your arrays, and check that within a filter of the other array:
const map2 = new Map(this.array2.map(x => [x.type, s]));
const intersect = this.array1.filter(a1 =>
map.has(a1.type));
This adds a little bit of complexity, but is more efficient for all but the simplest cases.
You can achieve what you want with the following simple example :
let accessLevels = [
{
description: "Properties",
type: '1',
selected: false
},
{
description: "Equipment",
type: '2',
selected: false
},
{
description: "Jobs",
type: '3',
selected: false
},
{
description: "Calender",
value: '4',
selected: false
}
]
let api = [
{
description: "Equipment",
type: '2'
},
{
description: "Jobs",
value: '3'
}
];
for(var i = 0; i < accessLevels.length; i++) {
accessLevels[i].selected = api.find(e => e.description === accessLevels[i].description) ? true : false;
}
console.log(accessLevels);
You can use Map collection to have O(1) while mapping the second array:
const unique = new Map(received.map(s => [s.description, s]));
const result = accessLevels.map(({ description, type})=>
({selected: (unique.get(description) ? true : false), type, description}))
An example:
let accessLevels = [
{
description: "Properties",
type: '1',
selected: false
},
{
description: "Equipment",
type: '2',
selected: false
},
{
description: "Jobs",
type: '3',
selected: false
},
{
description: "Calender",
type: '4',
selected: false
}
]
const received = [
{
description: "Equipment",
type: '2'
},
{
description: "Jobs",
value: '3'
}
];
const unique = new Map(received.map(s => [s.description, s]));
const result = accessLevels.map(({ description, type})=>
({selected: (unique.get(description) ? true : false), type, description}))
console.log(result);
I've made some changes to your code. Here's how it looks like:
async loadLandlordConfig(key: string) {
const result = await this.userService.loadLandlordConfig(key);
// assuming there's always a result.
// ACCESS_LEVELS is the list of your config.
accessLevels = result[0].accessLevels;
this.selectedApiValues = ACCESS_LEVELS.map((al: any) => {
const selected = accessLevels.findIndex(a => a.type === al.type) > -1;
return { ...al, selected }
})
}
This will give you with the value
this.selectedApiValues = [
{
description: "Properties",
type: '1',
selected: false
},
{
description: "Equipment",
type: '2',
selected: true
},
{
description: "Jobs",
type: '3',
selected: true
},
{
description: "Calender",
type: '4',
selected: false
}
]
I have a button that logs an event. When the button is clicked it automatically picks the chosen date from a calendar. after this the user would have to register two boolean attributes. I don't know how to do this efficiently. Can someone help me?
async cadastrarPresenca() {
let ida: boolean;
let volta: boolean;
const alert = await this.alertController.create({
header: 'Confirmar ida e/ou volta',
inputs: [
{
name: 'Ida',
type: 'checkbox',
label: 'Ida',
value: ida,
},
{
name: 'Volta',
type: 'checkbox',
label: 'Volta',
value: volta
}],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
handler: () => {
let start = this.dataSelecionada;
let end = this.dataSelecionada;
end.setMinutes(end.getMinutes() + 60);
let presenca = {
title: 'Event #' + start.getMinutes(),
startTime: start,
endTime: end,
allDay: false,
ida: ida,
volta: volta
};
this.firestore.collection('aluno').doc(this.authService.getUsuario().uid).collection('presenca').add(presenca);
}
}
]
});
await alert.present();
You just need to update your ok handler so that the data is passed in and then you can use it:
async cadastrarPresenca() {
let ida: boolean;
let volta: boolean;
const alert = await this.alertController.create({
header: 'Confirmar ida e/ou volta',
inputs: [
{
name: 'Ida',
type: 'checkbox',
label: 'Ida',
value: ida,
},
{
name: 'Volta',
type: 'checkbox',
label: 'Volta',
value: volta
}],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
// NEW CODE HERE
handler: (inputData) => {
console.log(inputData);
console.log(inputData["Volta"].checked);
// END OF NEW CODE HERE
let start = this.dataSelecionada;
let end = this.dataSelecionada;
end.setMinutes(end.getMinutes() + 60);
let presenca = {
title: 'Event #' + start.getMinutes(),
startTime: start,
endTime: end,
allDay: false,
ida: ida,
volta: volta
};
this.firestore.collection('aluno').doc(this.authService.getUsuario().uid).collection('presenca').add(presenca);
}
}
]
});
await alert.present();
So the new code is all that I've changed from your snippet:
// NEW CODE HERE
handler: (inputData) => {
console.log(inputData);
console.log(inputData["Volta"].checked);
// END OF NEW CODE HERE
You can look at the code that Ionic is built on for reference to see what options should be available, or just check out the first console.log I added.
I have an nested object array like this.
here is my array:
public collections: ICollections[] = [
{
collectionName: 'Brands',
collectionFields: [
{
columnTitle : 'brandTitle',
Type : dtEnum.string,
control: {
controlTitle: controlsEnum.input,
controlType: controlsEnum.input,
controlProperties:
{
placeholder: 'Enter brand title here ...',
type: 'text',
autocomplete: false,
}
},
columnWidth: 200
}
],
collectionFieldValidation: [{name: 'test'}],
hasPaginator: true,
stickyColumn: 0,
stickyHeader: true
},
{
columnTitle : 'brandURL',
Type : dtEnum.string,
control: {
controlTitle: controlsEnum.input,
controlType: controlsEnum.input,
controlProperties: {
placeHolder: 'Enter Brand URL',
type: 'text',
autocomplete: false,
}
},
columnWidth: 300
},
{
columnTitle : 'brandDescription',
Type : dtEnum.string,
control: {
controlTitle: controlsEnum.textarea,
controlType: controlsEnum.textarea,
controlProperties: {
placeHolder: 'Enter Brand Description',
type: 'text',
autocomplete: false,
}
},
columnWidth: 300
}
];
I want to reach to placeholder field. how do I find it by having only collectionName field with Brands value and columnTitle field with brandURL value ?
this question asked before just with collectionName field value but I find out that my filter should include more than one field.
first of all, find the collection that corresponds to "Brands" or any other thing:
let result = collections.find(p => p.collectionName === "Brands");
then get the placeholder field:
change your_index to 0 or your specific index
if (result) {
let placeholder = result.collectionFields[your_index].control.controlProperties.placeholder;
}
Here is my solution :
placeholder_finder(collectionSearchKey: string, fieldSearchKey: string): string {
let field: any;
let placeholder: string;
const obj = this.genInfo.collections.filter(
x => x.collectionName === collectionSearchKey
);
obj.forEach(data => {
field = data.collectionFields.filter(
x => x.columnTitle === fieldSearchKey
);
});
field.forEach(element => {
placeholder = element.control.controlProperties.placeHolder;
});
return placeholder;
}
Here I'm trying to get the current path, but also have problem and says that Cannot read property 'replace' of undefined. Who could help me to resolve this problem ?
handleClick= (event: SyntheticMouseEvent<HTMLButtonElement>) => {
const { workflowPath: _workflowPath } = this.props;
let workflowPath = _workflowPath;
Object.keys(this.props.row._original).forEach((key) => {
workflowPath = workflowPath.replace(`{${key}`, this.props.row._original[key]);
});
this.props.startFlow(workflowPath);
this.setState({ loading: true });
};
Also this handleClick is in component which is called Cell.
Header: 'Status',
accessor: 'status',
label: 'Change status',
type: 'workflow',
workflowPath: 'process/task/change_status',
icon: <Launch />,
items: [
{
label: 'New',
},
{
label: 'In progress',
},
{
label: 'Rejected',
},
{
label: 'Complete',
},
],
Cell: WorkflowColumn,
I believe it should be:
workflowPath && workflowPath.length &&
Object.keys(this.props.row._original).forEach((key) => {
...
This will check that workflowPath actually has something in it. If it's null this leads to the error you have been experiencing.