So far we have failed to globally handle the transaction nonces. The new ethers.js v5 comes with a NonceManager that helps us handling transaction nonces and automatically increases the nonce for each transaction.
103 lines
3.4 KiB
JavaScript
103 lines
3.4 KiB
JavaScript
const fetch = require('node-fetch');
|
|
|
|
function sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
module.exports = async function(robot, kredits) {
|
|
|
|
function messageRoom(message) {
|
|
robot.messageRoom(process.env.KREDITS_ROOM, message);
|
|
}
|
|
|
|
const { Contributor, Contribution } = kredits;
|
|
|
|
const kreditsContributionAmount = process.env.KREDITS_ZOOM_CONTRIBUTION_AMOUNT || 500;
|
|
const kreditsContributionKind = 'community';
|
|
|
|
const zoomAccessToken = process.env.KREDITS_ZOOM_JWT;
|
|
|
|
async function createContributionFor (displayName, meeting) {
|
|
const contributor = await getContributorByZoomDisplayName(displayName);
|
|
|
|
if (!contributor) {
|
|
robot.logger.info(`[hubot-kredits] Contributor not found: Zoom display name: ${displayName}`);
|
|
messageRoom(`I tried to add a contribution for zoom user ${displayName}, but did not find a matching contributor profile.`);
|
|
return Promise.resolve();
|
|
}
|
|
|
|
const contribution = {
|
|
contributorId: contributor.id,
|
|
contributorIpfsHash: contributor.ipfsHash,
|
|
amount: kreditsContributionAmount,
|
|
kind: kreditsContributionKind,
|
|
description: 'Team/Community Call',
|
|
date: meeting.end_time.split('T')[0],
|
|
time: meeting.end_time.split('T')[1]
|
|
}
|
|
|
|
return Contribution.add(contribution)
|
|
.then(tx => {
|
|
robot.logger.info(`[hubot-kredits] Contribution created: ${tx.hash}`);
|
|
})
|
|
.catch(error => {
|
|
robot.logger.error(`[hubot-kredits] Adding contribution for Zoom call failed:`, error);
|
|
});
|
|
}
|
|
|
|
function getContributorByZoomDisplayName(displayName) {
|
|
return Contributor.findByAccount({ site: 'zoom.us', username: displayName });
|
|
}
|
|
|
|
function request(path) {
|
|
return fetch(
|
|
`https://api.zoom.us/v2${path}`,
|
|
{headers: {authorization: `Bearer ${zoomAccessToken}`}}
|
|
);
|
|
}
|
|
|
|
function getMeetingParticipants(meetingUUID) {
|
|
return request(`/past_meetings/${meetingUUID}/participants`)
|
|
.then(response => response.json())
|
|
.then(json => json.participants)
|
|
}
|
|
|
|
function getMeetingDetails(meetingUUID) {
|
|
return request(`/past_meetings/${meetingUUID}`)
|
|
.then(r => r.json());
|
|
}
|
|
|
|
async function handleZoomMeetingEnded(data) {
|
|
const meetingDetails = await getMeetingDetails(data.uuid);
|
|
const participants = await getMeetingParticipants(data.uuid);
|
|
const names = Array.from(new Set(participants.map(p => p.name)));
|
|
|
|
if (meetingDetails.duration < 15 || names.length < 3) {
|
|
robot.logger.info(`[hubot-kredits] Ignoring zoom call ${data.uuid} (duration: ${meetingDetails.duration}, participants_count: ${meetingDetails.participants_count})`);
|
|
return;
|
|
}
|
|
|
|
for (const displayName of names) {
|
|
await createContributionFor(displayName, meetingDetails);
|
|
await sleep(60000); // potentially to prevent too many transactions at the sametime. transactions need to be ordered because of the nonce. not sure though if this is needed.
|
|
};
|
|
}
|
|
|
|
robot.router.post('/incoming/kredits/zoom/'+process.env.KREDITS_WEBHOOK_TOKEN, (req, res) => {
|
|
let data = req.body;
|
|
const eventName = data.event;
|
|
const payload = data.payload;
|
|
const object = payload.object;
|
|
|
|
|
|
if (eventName === 'meeting.ended' && (
|
|
!process.env.KREDITS_ZOOM_MEETING_WHITELIST ||
|
|
process.env.KREDITS_ZOOM_MEETING_WHITELIST.split(',').includes(object.id)
|
|
)) {
|
|
handleZoomMeetingEnded(object);
|
|
}
|
|
|
|
res.sendStatus(200);
|
|
})
|
|
}
|