I'm trying to create an anti-crash function, but got confused at the moment that the channel does not return the author. How can I get the author in another way?
I tried to connect to AuditLogEvent, but it didn't work
My code:
const { AuditLogEvent } = requier('discord.js')
const usersMap = new Map();
const LIMIT = 3;
const TIMES = 10000
bot.rest.on('channelDelete', async channel => {
const fetchedLogs = await channel.guild.fetchAuditLogs({
limit: 1,
type: AuditLogEvent.ChannelDelete,
})
const deletionLog = fetchedLogs.entries.first();
const { executor, target } = deletionLog
if(channel.guild.id != "940990129307263046") return
if(usersMap.has(executor.id)) {
const userData = usersMap.get(executor.id);
const { lastDelete, timer } = userData;
let deleteCount = userData.deleteCount;
const tim = channel.createdTimestamp - lastDelete.createdTimestamp
if(tim > TIMES) {
usersMap.delete(executor.id)
} else {
++deleteCount;
if(parseInt(deleteCount) === LIMIT) {
executor.ban()
}
}
}
})
Good evening! I have a problem.
I am creating a collection of NFTs using this js file.
What I am trying to modify is that once it reads the images in the layers folder, creates the final image and writes the metadata, these read and used images are deleted in the source folder (${basePath}/layers).
const basePath = process.cwd();
const { NETWORK } = require(`${basePath}/constants/network.js`);
const fs = require("fs");
const sha1 = require(`${basePath}/node_modules/sha1`);
const { createCanvas, loadImage } = require(`${basePath}/node_modules/canvas`);
const buildDir = `${basePath}/build`;
const layersDir = `${basePath}/layers`;
const {
format,
baseUri,
description,
background,
uniqueDnaTorrance,
layerConfigurations,
rarityDelimiter,
shuffleLayerConfigurations,
debugLogs,
extraMetadata,
text,
namePrefix,
network,
solanaMetadata,
gif,
} = require(`${basePath}/src/config.js`);
const canvas = createCanvas(format.width, format.height);
const ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = format.smoothing;
var metadataList = [];
var attributesList = [];
var dnaList = new Set();
const DNA_DELIMITER = "-";
const HashlipsGiffer = require(`${basePath}/modules/HashlipsGiffer.js`);
let hashlipsGiffer = null;
const buildSetup = () => {
if (fs.existsSync(buildDir)) {
fs.rmdirSync(buildDir, { recursive: true });
}
fs.mkdirSync(buildDir);
fs.mkdirSync(`${buildDir}/json`);
fs.mkdirSync(`${buildDir}/images`);
if (gif.export) {
fs.mkdirSync(`${buildDir}/gifs`);
}
};
const getRarityWeight = (_str) => {
let nameWithoutExtension = _str.slice(0, -4);
var nameWithoutWeight = Number(
nameWithoutExtension.split(rarityDelimiter).pop()
);
if (isNaN(nameWithoutWeight)) {
nameWithoutWeight = 1;
}
return nameWithoutWeight;
};
const cleanDna = (_str) => {
const withoutOptions = removeQueryStrings(_str);
var dna = Number(withoutOptions.split(":").shift());
return dna;
};
const cleanName = (_str) => {
let nameWithoutExtension = _str.slice(0, -4);
var nameWithoutWeight = nameWithoutExtension.split(rarityDelimiter).shift();
return nameWithoutWeight;
};
const getElements = (path) => {
return fs
.readdirSync(path)
.filter((item) => !/(^|\/)\.[^\/\.]/g.test(item))
.map((i, index) => {
return {
id: index,
name: cleanName(i),
filename: i,
path: `${path}${i}`,
weight: getRarityWeight(i),
};
});
};
const layersSetup = (layersOrder) => {
const layers = layersOrder.map((layerObj, index) => ({
id: index,
elements: getElements(`${layersDir}/${layerObj.name}/`),
name:
layerObj.options?.["displayName"] != undefined
? layerObj.options?.["displayName"]
: layerObj.name,
blend:
layerObj.options?.["blend"] != undefined
? layerObj.options?.["blend"]
: "source-over",
opacity:
layerObj.options?.["opacity"] != undefined
? layerObj.options?.["opacity"]
: 1,
bypassDNA:
layerObj.options?.["bypassDNA"] !== undefined
? layerObj.options?.["bypassDNA"]
: false,
}));
return layers;
};
const saveImage = (_editionCount) => {
fs.writeFileSync(
`${buildDir}/images/${_editionCount}.png`,
canvas.toBuffer("image/png")
);
};
const genColor = () => {
let hue = Math.floor(Math.random() * 360);
let pastel = `hsl(${hue}, 100%, ${background.brightness})`;
return pastel;
};
const drawBackground = () => {
ctx.fillStyle = background.static ? background.default : genColor();
ctx.fillRect(0, 0, format.width, format.height);
};
const addMetadata = (_dna, _edition) => {
let dateTime = Date.now();
let tempMetadata = {
name: `${namePrefix} #${_edition}`,
description: description,
image: `${baseUri}/${_edition}.png`,
dna: sha1(_dna),
edition: _edition,
date: dateTime,
...extraMetadata,
attributes: attributesList,
compiler: "CryptoGioconda Engine",
};
if (network == NETWORK.sol) {
tempMetadata = {
//Added metadata for solana
name: tempMetadata.name,
symbol: solanaMetadata.symbol,
description: tempMetadata.description,
//Added metadata for solana
seller_fee_basis_points: solanaMetadata.seller_fee_basis_points,
image: `image.png`,
//Added metadata for solana
external_url: solanaMetadata.external_url,
edition: _edition,
...extraMetadata,
attributes: tempMetadata.attributes,
properties: {
files: [
{
uri: "image.png",
type: "image/png",
},
],
category: "image",
creators: solanaMetadata.creators,
},
};
}
metadataList.push(tempMetadata);
attributesList = [];
};
const addAttributes = (_element) => {
let selectedElement = _element.layer.selectedElement;
attributesList.push({
trait_type: _element.layer.name,
value: selectedElement.name,
});
};
const loadLayerImg = async (_layer) => {
return new Promise(async (resolve) => {
const image = await loadImage(`${_layer.selectedElement.path}`);
resolve({ layer: _layer, loadedImage: image });
});
};
const addText = (_sig, x, y, size) => {
ctx.fillStyle = text.color;
ctx.font = `${text.weight} ${size}pt ${text.family}`;
ctx.textBaseline = text.baseline;
ctx.textAlign = text.align;
ctx.fillText(_sig, x, y);
};
const drawElement = (_renderObject, _index, _layersLen) => {
ctx.globalAlpha = _renderObject.layer.opacity;
ctx.globalCompositeOperation = _renderObject.layer.blend;
text.only
? addText(
`${_renderObject.layer.name}${text.spacer}${_renderObject.layer.selectedElement.name}`,
text.xGap,
text.yGap * (_index + 1),
text.size
)
: ctx.drawImage(
_renderObject.loadedImage,
0,
0,
format.width,
format.height
);
addAttributes(_renderObject);
};
const constructLayerToDna = (_dna = "", _layers = []) => {
let mappedDnaToLayers = _layers.map((layer, index) => {
let selectedElement = layer.elements.find(
(e) => e.id == cleanDna(_dna.split(DNA_DELIMITER)[index])
);
return {
name: layer.name,
blend: layer.blend,
opacity: layer.opacity,
selectedElement: selectedElement,
};
});
return mappedDnaToLayers;
};
/**
* In some cases a DNA string may contain optional query parameters for options
* such as bypassing the DNA isUnique check, this function filters out those
* items without modifying the stored DNA.
*
* #param {String} _dna New DNA string
* #returns new DNA string with any items that should be filtered, removed.
*/
const filterDNAOptions = (_dna) => {
const dnaItems = _dna.split(DNA_DELIMITER);
const filteredDNA = dnaItems.filter((element) => {
const query = /(\?.*$)/;
const querystring = query.exec(element);
if (!querystring) {
return true;
}
const options = querystring[1].split("&").reduce((r, setting) => {
const keyPairs = setting.split("=");
return { ...r, [keyPairs[0]]: keyPairs[1] };
}, []);
return options.bypassDNA;
});
return filteredDNA.join(DNA_DELIMITER);
};
/**
* Cleaning function for DNA strings. When DNA strings include an option, it
* is added to the filename with a ?setting=value query string. It needs to be
* removed to properly access the file name before Drawing.
*
* #param {String} _dna The entire newDNA string
* #returns Cleaned DNA string without querystring parameters.
*/
const removeQueryStrings = (_dna) => {
const query = /(\?.*$)/;
return _dna.replace(query, "");
};
const isDnaUnique = (_DnaList = new Set(), _dna = "") => {
const _filteredDNA = filterDNAOptions(_dna);
return !_DnaList.has(_filteredDNA);
};
const createDna = (_layers) => {
let randNum = [];
_layers.forEach((layer) => {
var totalWeight = 0;
layer.elements.forEach((element) => {
totalWeight += element.weight;
});
// number between 0 - totalWeight
let random = Math.floor(Math.random() * totalWeight);
for (var i = 0; i < layer.elements.length; i++) {
// subtract the current weight from the random weight until we reach a sub zero value.
random -= layer.elements[i].weight;
if (random < 0) {
return randNum.push(
`${layer.elements[i].id}:${layer.elements[i].filename}${
layer.bypassDNA ? "?bypassDNA=true" : ""
}`
);
}
}
});
return randNum.join(DNA_DELIMITER);
};
const writeMetaData = (_data) => {
fs.writeFileSync(`${buildDir}/json/_metadata.json`, _data);
};
const saveMetaDataSingleFile = (_editionCount) => {
let metadata = metadataList.find((meta) => meta.edition == _editionCount);
debugLogs
? console.log(
`Writing metadata for ${_editionCount}: ${JSON.stringify(metadata)}`
)
: null;
fs.writeFileSync(
`${buildDir}/json/${_editionCount}.json`,
JSON.stringify(metadata, null, 2)
);
};
function shuffle(array) {
let currentIndex = array.length,
randomIndex;
while (currentIndex != 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
[array[currentIndex], array[randomIndex]] = [
array[randomIndex],
array[currentIndex],
];
}
return array;
}
const startCreating = async () => {
let layerConfigIndex = 0;
let editionCount = 1;
let failedCount = 0;
let abstractedIndexes = [];
for (
let i = network == NETWORK.sol ? 0 : 1;
i <= layerConfigurations[layerConfigurations.length - 1].growEditionSizeTo;
i++
) {
abstractedIndexes.push(i);
}
if (shuffleLayerConfigurations) {
abstractedIndexes = shuffle(abstractedIndexes);
}
debugLogs
? console.log("Editions left to create: ", abstractedIndexes)
: null;
while (layerConfigIndex < layerConfigurations.length) {
const layers = layersSetup(
layerConfigurations[layerConfigIndex].layersOrder
);
while (
editionCount <= layerConfigurations[layerConfigIndex].growEditionSizeTo
) {
let newDna = createDna(layers);
if (isDnaUnique(dnaList, newDna)) {
let results = constructLayerToDna(newDna, layers);
let loadedElements = [];
results.forEach((layer) => {
loadedElements.push(loadLayerImg(layer));
});
await Promise.all(loadedElements).then((renderObjectArray) => {
debugLogs ? console.log("Clearing canvas") : null;
ctx.clearRect(0, 0, format.width, format.height);
if (gif.export) {
hashlipsGiffer = new HashlipsGiffer(
canvas,
ctx,
`${buildDir}/gifs/${abstractedIndexes[0]}.gif`,
gif.repeat,
gif.quality,
gif.delay
);
hashlipsGiffer.start();
}
if (background.generate) {
drawBackground();
}
renderObjectArray.forEach((renderObject, index) => {
drawElement(
renderObject,
index,
layerConfigurations[layerConfigIndex].layersOrder.length
);
if (gif.export) {
hashlipsGiffer.add();
}
});
if (gif.export) {
hashlipsGiffer.stop();
}
debugLogs
? console.log("Editions left to create: ", abstractedIndexes)
: null;
saveImage(abstractedIndexes[0]);
addMetadata(newDna, abstractedIndexes[0]);
saveMetaDataSingleFile(abstractedIndexes[0]);
console.log(
`Created edition: ${abstractedIndexes[0]}, with DNA: ${sha1(
newDna
)}`
);
});
dnaList.add(filterDNAOptions(newDna));
editionCount++;
abstractedIndexes.shift();
} else {
console.log("DNA exists!");
failedCount++;
if (failedCount >= uniqueDnaTorrance) {
console.log(
`You need more layers or elements to grow your edition to ${layerConfigurations[layerConfigIndex].growEditionSizeTo} artworks!`
);
process.exit();
}
}
}
layerConfigIndex++;
}
writeMetaData(JSON.stringify(metadataList, null, 2));
};
module.exports = { startCreating, buildSetup, getElements };
I tried to use this code by inserting it inside the main document, but it doesn't work.
try {
fs.unlinkSync(path)
//file removed
} catch(err) {
console.error(err)
}
Can anyone tell me how can I solve?
In the line setVotedPosts([...previousVotedPosts, postId]);
I'm trying to get the previous value of votedPosts, but I'm getting back the newest value.
full code : https://github.com/silvertechguy/reddit-clone/blob/main/src/components/vote-buttons.js
App live : https://reddit-clone-official.vercel.app/
const VoteButtons = ({ post }) => {
const [isVoting, setVoting] = useState(false);
const [votedPosts, setVotedPosts] = useState([]);
useEffect(() => {
const votesFromLocalStorage =
JSON.parse(localStorage.getItem("votes")) || [];
setVotedPosts(votesFromLocalStorage);
}, []);
const handleDisablingOfVoting = (postId) => {
const previousVotedPosts = votedPosts;
setVotedPosts([...previousVotedPosts, postId]);
localStorage.setItem(
"votes",
JSON.stringify([...previousVotedPosts, postId])
);
};
const handleClick = async (type) => {
setVoting(true);
// Do calculation to save the vote.
let upVotesCount = post.upVotesCount;
let downVotesCount = post.downVotesCount;
const date = new Date();
if (type === "upvote") {
upVotesCount = upVotesCount + 1;
} else {
downVotesCount = downVotesCount + 1;
}
await db.collection("posts").doc(post.id).set({
title: post.title,
upVotesCount,
downVotesCount,
createdAt: post.createdAt,
updatedAt: date.toUTCString(),
});
// Disable the voting button once the voting is successful.
handleDisablingOfVoting(post.id);
setVoting(false);
};
const checkIfPostIsAlreadyVoted = () => votedPosts.includes(post.id);
Problem
const previousVotedPosts = votedPosts;
In JavaScript, arrays are reference types, so you can't just create a new copy of an array using =.
Try this solution
Clone array using spread syntax(...).
const handleDisablingOfVoting = (postId) => {
const previousVotedPosts = [...votedPosts];
setVotedPosts([...previousVotedPosts, postId]);
localStorage.setItem(
"votes",
JSON.stringify([...previousVotedPosts, postId])
);
};
I have an API call in api.js:
export const getGraphData = (domain, userId, testId) => {
return axios({
url: `${domain}/api/${c.embedConfig.apiVersion}/member/${userId}/utests/${testId}`,
method: 'get',
});
};
I have a React helper that takes that data and transforms it.
import { getGraphData } from './api';
const dataObj = (domain, userId, testId) => {
const steps = getGraphData(domain, userId, testId)
.then((result) => {
return result.attributes;
});
console.log(steps);
// const steps = test.get('steps');
const expr = /select/;
// build array of steps that we have results in
const resultsSteps = [];
steps.forEach((step) => {
// check for types that contain 'select', and add them to array
if (expr.test(step.get('type'))) {
resultsSteps.push(step);
}
});
const newResultsSteps = [];
resultsSteps.forEach((item, i) => {
const newMapStep = new Map();
const itemDescription = item.get('description');
const itemId = item.get('id');
const itemOptions = item.get('options');
const itemAnswers = item.get('userAnswers');
const newOptArray = [];
itemOptions.forEach((element) => {
const optionsMap = new Map();
let elemName = element.get('value');
if (!element.get('value')) { elemName = element.get('caption'); }
const elemPosition = element.get('position');
const elemCount = element.get('count');
optionsMap.name = elemName;
optionsMap.position = elemPosition;
optionsMap.value = elemCount;
newOptArray.push(optionsMap);
});
newMapStep.chartType = 'horizontalBar';
newMapStep.description = itemDescription;
newMapStep.featured = 'false';
newMapStep.detailUrl = '';
newMapStep.featuredStepIndex = i + 1;
newMapStep.id = itemId;
newMapStep.isValid = 'false';
newMapStep.type = 'results';
const listForNewOptArray = List(newOptArray);
newMapStep.data = listForNewOptArray;
newMapStep.userAnswers = itemAnswers;
newResultsSteps.push(newMapStep);
});
return newResultsSteps;
};
export default dataObj;
The issue is steps, when logged outside the .then() returns a Promise {<pending>}. If I log results.attributes inside the .then(), I see the data fully returned.
You need to wait until your async call is resolved. You can do this by chaining on another then:
getGraphData(domain, userId, testId)
.then((result) => {
return result.attributes;
})
.then(steps => {
// put the rest of your method here
});
You can also look at async/await if your platform supports it which would allow code closer to your original
const steps = await getGraphData(domain, userId, testId)
.then((result) => {
return result.attributes;
});
// can use steps here
You have 2 options to transform your fetched data :
1st option : create a async function that returns a promise with the modified data :
const dataObj = (domain, userId, testId) => {
return getGraphData(domain, userId, testId).then((result) => {
const steps = result.attributes;
const expr = /select/;
// build array of steps that we have results in
const resultsSteps = [];
steps.forEach((step) => {
// check for types that contain 'select', and add them to array
if (expr.test(step.get('type'))) {
resultsSteps.push(step);
}
});
const newResultsSteps = [];
resultsSteps.forEach((item, i) => {
const newMapStep = new Map();
const itemDescription = item.get('description');
const itemId = item.get('id');
const itemOptions = item.get('options');
const itemAnswers = item.get('userAnswers');
const newOptArray = [];
itemOptions.forEach((element) => {
const optionsMap = new Map();
let elemName = element.get('value');
if (!element.get('value')) {
elemName = element.get('caption');
}
const elemPosition = element.get('position');
const elemCount = element.get('count');
optionsMap.name = elemName;
optionsMap.position = elemPosition;
optionsMap.value = elemCount;
newOptArray.push(optionsMap);
});
newMapStep.chartType = 'horizontalBar';
newMapStep.description = itemDescription;
newMapStep.featured = 'false';
newMapStep.detailUrl = '';
newMapStep.featuredStepIndex = i + 1;
newMapStep.id = itemId;
newMapStep.isValid = 'false';
newMapStep.type = 'results';
const listForNewOptArray = List(newOptArray);
newMapStep.data = listForNewOptArray;
newMapStep.userAnswers = itemAnswers;
newResultsSteps.push(newMapStep);
});
return newResultsSteps;
});
};
With es7 async/await syntax it should be :
const dataObj = async (domain, userId, testId) => {
const result = await getGraphData(domain, userId, testId);
const steps = result.attributes;
... modify the data
}
Then keep in mind that this function returns a promise, you'll need to wait for it to get the result, example in a react component :
componentDidMount(){
dataObj('mydomain', 'myuserId', 'mytestId').then((res) => {
this.setState({ data: res });
}
}
The component will update when the promise is resolve, you can then use the data (you'll need to handle the undefined data state in render method)
2nd option : Create a sync function to modify the data :
const dataObj = (steps) => {
const expr = /select/;
const resultsSteps = [];
steps.forEach((step) => {
...
}
return newResultsSteps;
};
To have the same result as option 1 in our component we'll use it like this :
componentDidMount(){
getGraphData('mydomain', 'myuserId', 'mytestId').then((res) => {
const modifiedData = dataObj(res);
this.setState({ data: modifiedData });
}
}
That's how promises work. The data is not ready when you are trying to use it so you should move all your processing into the .then. The reason your variable is a Promise {<pending>} is because you can chain other things onto it.
Something like:
steps.then((steps) => {
...
});
I'm trying to learn some CycleJS and I ended up not knowing what to do exactly with this. The goal is to create inputs via configuration, instead of declaring them manually. The problem is I'm only getting rendered the last of the inputs from the array, instead of both. I'm assume the error is in view$ and how I'm dealing with the stream.My naive implementation is this:
Main.js
const sliderGunProps$ = xs.of({
value: 30,
id: 'gun'
});
const sliderCannonProps$ = xs.of({
value: 70,
id: 'cannon'
});
const propsConfig = [sliderGunProps$, sliderCannonProps$];
function view$(state$) {
return xs.fromArray(state$)
.map(state => {
return xs.combine(state.sliderVDom$, state.values)
.map(([sliderVDom, value]) =>
div([sliderVDom, h1(value)])
);
})
.flatten();
}
function model(actions$) {
return actions$.map((action) => {
const sliderVDom$ = action.DOM;
const sliderValue$ = action.value;
const values$ = sliderValue$.map(val => val);
return {
sliderVDom$: sliderVDom$,
values: values$
};
});
}
function intent(sources) {
return propsConfig.map(prop$ => Slider({
DOM: sources.DOM,
props$: prop$
}));
}
function main(sources) {
const actions$ = intent(sources);
const state$ = model(actions$);
const vdom$ = view$(state$);
const sink = {
DOM: vdom$
};
return sink;
}
Thanks!
I ended up figuring out how to solve it. The point was that I was not understanding how view$ handle the streams. The proper code:
function total(values) {
return xs.combine(...values)
.map(val => val.reduce((acc, x) => acc + x));
}
function view$(state$) {
const DOMElements = state$.map(slider => slider.sliderVDom$);
const values = state$.map(slider => slider.values);
const totalValue$ = total(values);
return xs.combine(totalValue$, ...DOMElements)
.map(([totalValue, ...elements]) => (
div([
...elements,
h1(totalValue)
])
));
}
function model(actions$) {
return actions$.map((action) => ({
sliderVDom$: action.DOM,
values: action.value.map(val => val)
}));
}
function intent(sources) {
return propsConfig.map(prop$ => Slider({
DOM: sources.DOM,
props$: prop$
}));
}