43 Commits

Author SHA1 Message Date
ad0e34b990 3.8.0 2020-10-29 15:15:10 +01:00
063a9c6b37 Merge pull request #63 from 67P/bugfix/mediawiki_accident
Fix mediawiki integration
2020-10-29 15:13:12 +01:00
f05436e9b9 Fix mediawiki integration
Accidentally deleted a line in a recent PR, and it slipped through the
review.
2020-10-29 15:12:50 +01:00
e305643f69 Merge pull request #61 from 67P/chore/replace_deprecated_contract_calls
Replace deprecated contract API calls
2020-10-29 14:13:36 +01:00
82a003ffeb Merge pull request #62 from 67P/feature/wiki_changes
Only create small automatic contributions for wiki edits
2020-10-29 14:10:33 +01:00
fc0c113997 Only create small automatic contributions for wiki edits
We decided that it's too difficult for a machine to gauge the meaning
and value of wiki edits by line numbers, so automatic kredits are now
always a small contributions. Until we have new tools for larger wiki
contributions (e.g. mediawiki tags), we can create manual contributions
for those.
2020-10-29 12:56:49 +01:00
5c6540580b Replace deprecated contract API calls
Use the new method.
2020-10-29 12:07:42 +01:00
078f78417c 3.7.0 2020-07-18 13:06:48 +02:00
d870099059 Update to latest ethers.js patch release 2020-07-18 13:06:09 +02:00
b7482f2468 package-lock 2020-07-18 13:04:12 +02:00
94c256e3d9 Merge pull request #60 from 67P/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-07-18 12:59:15 +02:00
3b382eadb2 Merge pull request #59 from 67P/ethers-nonce-manager
Use new ethers.js NonceManager to handle transaction nonces
2020-07-18 12:58:45 +02:00
ec63980cd3 Use kredits-contracts 6.0.0 2020-07-17 13:50:37 +02:00
dependabot[bot]
2b86f37fcb Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-16 03:28:48 +00:00
a8e29f2197 Use ethers5 branch of kredits-contracts 2020-06-27 18:38:22 +02:00
b7ff55929c Use new ethers.js NonceManager to handle transaction nonces
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.
2020-06-27 18:24:44 +02:00
35f6acc150 3.6.0 2020-05-22 12:10:24 +02:00
095a1e0004 Merge pull request #56 from 67P/feature/zoom-meeting-whitelist
Add zoom meeting whitelist
2020-05-18 10:43:25 +02:00
95290a7715 Apply suggestions from code review
Co-authored-by: Sebastian Kippe <sebastian@kip.pe>
2020-05-14 12:13:38 +02:00
fca017c61a Add readme for zoom integration 2020-05-14 10:38:51 +02:00
fb1a471303 Make kredits amount for zoom calls configurable
defaults to 500 - a general small contribution
2020-05-14 10:33:13 +02:00
d82e2e9256 Revert "Update integrations/zoom.js"
This reverts commit 634dc207e6.
2020-05-14 10:00:00 +02:00
634dc207e6 Update integrations/zoom.js
Co-authored-by: Sebastian Kippe <sebastian@kip.pe>
2020-05-14 09:45:42 +02:00
6fd3989118 Add zoom meeting whitelist
This allows to only record meetings for certain whitelisted meeting ids
2020-04-30 16:19:49 +02:00
41f5aef460 3.5.1 2020-04-16 21:43:48 +02:00
c121713a13 Merge pull request #54 from 67P/bugfix/ignore-small-meetings
Ignore meetings that have less than 3 unique participants
2020-04-16 21:17:16 +02:00
e10dd4abc3 Ignore meetings that have less than 3 unique participants
zoom's participants_count is not unique and the same person can be counted
multiple times.
We need to check for unique names.
2020-04-16 18:07:17 +02:00
e823797ee2 3.5.0 2020-04-16 17:40:46 +02:00
7d3c2cae19 Merge branch 'feature/zoom' 2020-04-16 17:34:31 +02:00
960dcb55de Moar await 2020-04-16 17:33:53 +02:00
60ed697460 Add comment when tx is undefined
We createContributionFor() simply returns if no contributor is found.
2020-04-16 17:17:40 +02:00
7f653f23ce typo 2020-04-16 17:08:26 +02:00
98ff61ab0a Add handling of missing zoom profiles 2020-04-16 17:03:03 +02:00
e7f8723f6e Make sure zoom participants are unique
to make sure we only create one contribution per participants
2020-04-16 16:36:32 +02:00
164782bd25 Only load Zoom integration when JWT configured 2020-04-16 12:18:52 +02:00
8f961bb102 Apply suggestions from code review
Co-Authored-By: Sebastian Kippe <sebastian@kip.pe>
2020-04-16 12:08:50 +02:00
c4ef8de018 Nicer log messages
Co-Authored-By: Sebastian Kippe <sebastian@kip.pe>
2020-04-16 12:08:06 +02:00
110c4384e0 Autoload zoom integration 2020-04-15 21:51:02 +02:00
70ea031b31 Zoom integration using the JWT API 2020-04-15 21:29:21 +02:00
ab8d043593 Merge pull request #52 from 67P/dependabot/npm_and_yarn/kind-of-6.0.3
Bump kind-of from 6.0.2 to 6.0.3
2020-03-31 19:56:23 -05:00
dependabot[bot]
8b5c2a3274 Bump kind-of from 6.0.2 to 6.0.3
Bumps [kind-of](https://github.com/jonschlinkert/kind-of) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/jonschlinkert/kind-of/releases)
- [Changelog](https://github.com/jonschlinkert/kind-of/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jonschlinkert/kind-of/compare/6.0.2...6.0.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-01 00:54:28 +00:00
5cc0116163 Skeleton of the zoom integration
using the new zoom API
2020-02-27 15:48:55 +01:00
708f0b6622 Add release-drafter config 2019-09-01 17:06:38 +02:00
9 changed files with 1643 additions and 623 deletions

4
.github/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
template: |
## Changes
$CHANGES

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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"