Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
ad0e34b990
|
|||
| 063a9c6b37 | |||
|
f05436e9b9
|
|||
| e305643f69 | |||
| 82a003ffeb | |||
|
fc0c113997
|
|||
|
5c6540580b
|
|||
| 078f78417c | |||
| d870099059 | |||
| b7482f2468 | |||
| 94c256e3d9 | |||
| 3b382eadb2 | |||
| ec63980cd3 | |||
|
|
2b86f37fcb | ||
| a8e29f2197 | |||
| b7ff55929c | |||
| 35f6acc150 | |||
| 095a1e0004 | |||
| 95290a7715 | |||
| fca017c61a | |||
| fb1a471303 | |||
| d82e2e9256 | |||
| 634dc207e6 | |||
| 6fd3989118 | |||
| 41f5aef460 | |||
| c121713a13 | |||
| e10dd4abc3 | |||
| e823797ee2 | |||
| 7d3c2cae19 | |||
| 960dcb55de | |||
| 60ed697460 | |||
| 7f653f23ce | |||
| 98ff61ab0a | |||
| e7f8723f6e | |||
| 164782bd25 | |||
| 8f961bb102 | |||
| c4ef8de018 | |||
| 110c4384e0 | |||
| 70ea031b31 | |||
| ab8d043593 | |||
|
|
8b5c2a3274 | ||
| 5cc0116163 | |||
| 708f0b6622 |
4
.github/release-drafter.yml
vendored
Normal file
4
.github/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
template: |
|
||||
## Changes
|
||||
|
||||
$CHANGES
|
||||
26
README.md
26
README.md
@@ -116,3 +116,29 @@ wiki's API on its own.
|
||||
|
||||
[kredits-contracts]: https://github.com/67P/kredits-contracts
|
||||
[GitHub OAuth app]: https://developer.github.com/apps/about-apps/#about-oauth-apps
|
||||
|
||||
|
||||
### Zoom
|
||||
|
||||
The Zoom integration creates contributions for meeting participations.
|
||||
|
||||
Every meeting that is longer than 15 minutes and with more than 2 participants will be registered.
|
||||
An optional meeting whitelist can be configured to create contributions only for specific meetings.
|
||||
|
||||
|
||||
#### Setup
|
||||
|
||||
A Zoom JWT app has to be set up and an [event webhook subscription](https://marketplace.zoom.us/docs/api-reference/webhook-reference/meeting-events/meeting-ending")
|
||||
on `meeting.ended` has to be configured to the following URL:
|
||||
|
||||
https://your-hubot.example.com/incoming/kredits/zoom/{webhook_token}
|
||||
|
||||
#### Config
|
||||
|
||||
| Key | Description |
|
||||
| --- | --- |
|
||||
| `KREDITS_ZOOM_JWT` | The JWT for the Zoom application (required)
|
||||
| `KREDITS_ZOOM_MEETING_WHITELIST` | Comma separated list of meeting names for which kredits should be tracked (optional)
|
||||
| `KREDITS_ZOOM_CONTRIBUTION_AMOUNT` | The amount of kredits issued for each meeting. (default: 500)
|
||||
|
||||
[Zoom apps](https://marketplace.zoom.us/user/build)
|
||||
|
||||
7
index.js
7
index.js
@@ -2,6 +2,7 @@ const fs = require('fs');
|
||||
const util = require('util');
|
||||
const fetch = require('node-fetch');
|
||||
const ethers = require('ethers');
|
||||
const NonceManager = require('@ethersproject/experimental').NonceManager;
|
||||
const Kredits = require('kredits-contracts');
|
||||
|
||||
const walletPath = process.env.KREDITS_WALLET_PATH || './wallet.json';
|
||||
@@ -43,7 +44,7 @@ module.exports = async function(robot) {
|
||||
} else {
|
||||
ethProvider = new ethers.getDefaultProvider('rinkeby');
|
||||
}
|
||||
const signer = wallet.connect(ethProvider);
|
||||
const signer = new NonceManager(wallet.connect(ethProvider));
|
||||
|
||||
//
|
||||
// Kredits contracts setup
|
||||
@@ -152,6 +153,10 @@ module.exports = async function(robot) {
|
||||
require('./integrations/github')(robot, kredits);
|
||||
require('./integrations/gitea')(robot, kredits);
|
||||
|
||||
if (typeof process.env.KREDITS_ZOOM_JWT !== 'undefined') {
|
||||
require('./integrations/zoom')(robot, kredits);
|
||||
}
|
||||
|
||||
if (typeof process.env.KREDITS_MEDIAWIKI_URL !== 'undefined') {
|
||||
require('./integrations/mediawiki')(robot, kredits);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const util = require('util');
|
||||
const fetch = require('node-fetch');
|
||||
const amountFromLabels = require('./utils/amount-from-labels');
|
||||
const kindFromLabels = require('./utils/kind-from-labels');
|
||||
|
||||
@@ -56,7 +55,7 @@ module.exports = async function(robot, kredits) {
|
||||
robot.logger.debug(`[hubot-kredits] contribution attributes:`);
|
||||
robot.logger.debug(util.inspect(contributionAttr, { depth: 1, colors: true }));
|
||||
|
||||
return Contribution.addContribution(contributionAttr).catch(error => {
|
||||
return Contribution.add(contributionAttr).catch(error => {
|
||||
robot.logger.error(`[hubot-kredits] Error:`, error);
|
||||
messageRoom(`I tried to add a contribution for ${giteaUser} for ${url}, but I encountered an error when submitting the tx:`);
|
||||
messageRoom(error.message);
|
||||
|
||||
@@ -61,7 +61,7 @@ module.exports = async function(robot, kredits) {
|
||||
robot.logger.debug(`[hubot-kredits] contribution attributes:`);
|
||||
robot.logger.debug(util.inspect(contributionAttr, { depth: 1, colors: true }));
|
||||
|
||||
return Contribution.addContribution(contributionAttr).catch(error => {
|
||||
return Contribution.add(contributionAttr).catch(error => {
|
||||
robot.logger.error(`[hubot-kredits] Error:`, error);
|
||||
messageRoom(`I tried to add a contribution for ${githubUser} for ${url}, but I encountered an error when submitting the tx:`);
|
||||
messageRoom(error.message);
|
||||
|
||||
@@ -48,7 +48,7 @@ module.exports = async function(robot, kredits) {
|
||||
kind: 'docs'
|
||||
};
|
||||
|
||||
return Contribution.addContribution(contribution).catch(error => {
|
||||
return Contribution.add(contribution).catch(error => {
|
||||
robot.logger.error(`[hubot-kredits] Adding contribution failed:`, error);
|
||||
});
|
||||
}).catch(() => {
|
||||
@@ -126,6 +126,7 @@ module.exports = async function(robot, kredits) {
|
||||
return [...new Set(changes.map(c => `"${c.title}"`))].join(', ');
|
||||
}
|
||||
|
||||
// Currently not used
|
||||
function calculateAmountForChanges(details) {
|
||||
let amount;
|
||||
|
||||
@@ -144,9 +145,8 @@ module.exports = async function(robot, kredits) {
|
||||
const dateNow = new Date();
|
||||
const dateYesterday = dateNow.setDate(dateNow.getDate() - 1);
|
||||
const date = (new Date(dateYesterday)).toISOString().split('T')[0];
|
||||
|
||||
const details = analyzeUserChanges(user, changes);
|
||||
const amount = calculateAmountForChanges(details);
|
||||
const amount = 500;
|
||||
|
||||
let desc = `Added ${details.charsAdded} characters of text.`;
|
||||
if (details.pagesChanged.length > 0) {
|
||||
|
||||
102
integrations/zoom.js
Normal file
102
integrations/zoom.js
Normal file
@@ -0,0 +1,102 @@
|
||||
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);
|
||||
})
|
||||
}
|
||||
2109
package-lock.json
generated
2109
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hubot-kredits",
|
||||
"version": "3.4.1",
|
||||
"version": "3.8.0",
|
||||
"description": "Kosmos Kredits functionality for chat bots",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -12,13 +12,14 @@
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"eth-provider": "^0.2.2",
|
||||
"ethers": "^4.0.27",
|
||||
"ethers": "^5.0.5",
|
||||
"@ethersproject/experimental": "5.0.0",
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.16.2",
|
||||
"grant-express": "^4.6.1",
|
||||
"group-array": "^1.0.0",
|
||||
"kosmos-schemas": "^1.1.2",
|
||||
"kredits-contracts": "^5.4.0",
|
||||
"kredits-contracts": "^6.0.0",
|
||||
"node-cron": "^2.0.3",
|
||||
"node-fetch": "^2.3.0",
|
||||
"prompt": "^1.0.0"
|
||||
|
||||
Reference in New Issue
Block a user