Rename contributorId to recipientId #199

Merged
raucao merged 7 commits from chore/rename_recipient_for_reimbursements into master 2022-06-12 05:17:48 +00:00
26 changed files with 116 additions and 119 deletions
+25 -24
View File
@@ -5,23 +5,24 @@
This README outlines the details of collaborating on this Ember application. This README outlines the details of collaborating on this Ember application.
A short introduction of this app could easily go here. A short introduction of this app could easily go here.
## Prerequisites ## Development
### Prerequisites
You will need the following things properly installed on your computer. You will need the following things properly installed on your computer.
* [Git](https://git-scm.com/) * [Git](https://git-scm.com/)
* [Node.js](https://nodejs.org/) (with npm) * [Node.js](https://nodejs.org/) (with npm)
* [Ember CLI](https://ember-cli.com/) * [Ember CLI](https://ember-cli.com/)
* [Google Chrome](https://google.com/chrome/) * [Google Chrome](https://google.com/chrome/) (only for running tests)
## Installation ### Installation
* `git clone git@github.com:67P/kredits-web.git` this repository * `git clone git@github.com:67P/kredits-web.git` this repository
* `cd kredits-web` * `cd kredits-web`
* `npm install` * `npm install`
## Running / Development ### Building/running for development
* `ember serve` - by default kredits-web connects to the Ethreum Kovan network * `ember serve` - by default kredits-web connects to the Ethreum Kovan network
* Visit your app at [http://localhost:4200](http://localhost:4200). * Visit your app at [http://localhost:4200](http://localhost:4200).
@@ -29,11 +30,11 @@ You will need the following things properly installed on your computer.
See [working with locally deployed contracts](https://github.com/67P/kredits-web#working-with-locally-deployed-contracts) for details on how to develop with locally deployed contracts. See [working with locally deployed contracts](https://github.com/67P/kredits-web#working-with-locally-deployed-contracts) for details on how to develop with locally deployed contracts.
### Code Generators ### Code generators
Make use of the many generators for code, try `ember help generate` for more details Make use of the many generators for code, try `ember help generate` for more details
### Running Tests ### Running tests
* `ember test` * `ember test`
* `ember test --server` * `ember test --server`
@@ -55,17 +56,15 @@ _(You need collaborator permissions on the 5apps Deploy project.)_
`npm run deploy` `npm run deploy`
## Working with locally deployed contracts ### Working with locally deployed contracts
The smart contracts and their JavaScript wrapper library are developed in the The smart contracts and their JavaScript wrapper library are developed in the
[kredits-contracts](https://github.com/67P/kredits-contracts) repo/package. [kredits-contracts](https://github.com/67P/kredits-contracts) repo/package.
You can run `kredits-web` on your machine, against a local, simulated Ethereum You can run `kredits-web` on your machine, against a local, simulated
network, provided e.g. by [ganache](http://truffleframework.com/ganache/). blockchain. [kredits-contracts](https://github.com/67P/kredits-contracts)
contains all the tools to start and set up such a simulated network, as well as
[kredits-contracts](https://github.com/67P/kredits-contracts) holds all the tools to deploy the Kredits smart contracts to it.
to start and set up such a simulated network, as well as to deploy smart
contracts to it.
These are the basic steps to get up and running: These are the basic steps to get up and running:
@@ -78,31 +77,33 @@ Run a local IPFS deamon.
#### 2. kredits-contracts #### 2. kredits-contracts
Get your local Ethereum development node running. (See [kredits-contracts README](https://github.com/67P/kredits-contracts) Run a local devchain with test data. (See [kredits-contracts
for details. README](https://github.com/67P/kredits-contracts) for details.
* Clone [kredits-contracts](https://github.com/67P/kredits-contracts) * Clone [kredits-contracts](https://github.com/67P/kredits-contracts)
* `npm install` * `npm install`
* `npm run devchain` - runs a local development chain * `npm run devchain` - runs a local development chain
* `npm run bootstrap` - bootstrap runs deploys all the contracts * `npm run bootstrap` - deploys all contracts and seeds test data
* `npm link` - make the `kredits-contracts` module linkable as `kredits-contracts` on your machine (currently broken :( ) * `npm link` - makes the `kredits-contracts` module linkable as `kredits-contracts` on your machine
#### 3. kredits-web #### 3. kredits-web
With IPFS and Ethereum/ganache running, you can now start this Ember app. With IPFS and the local devchain running, you can now link the contracts and
start the Ember app:
* `npm link kredits-contracts` - link the local `kredits-contracts` package * `npm link kredits-contracts` - links the local `kredits-contracts` package (has to be done again after every `npm install`)
* `npm run start:local` - WEB3_PROVIDER_URL=http://localhost:8545 must be set for local settings * `npm run start:local` - runs the Ember app with WEB3_PROVIDER_URL=http://localhost:8545 set
#### 4. Metamask network #### 4. Metamask network
Switch the network in Metamask to "Custom RPC" with the RPC URL `http://localhost:8545`. If you want to interact with the local contracts via a Web3 wallet, switch the
network to a "Custom RPC" one, with the RPC URL `http://localhost:8545`.
#### IPFS #### IPFS
Install IPFS with your favorite package manager and run If you haven't configured your IPFS node for CORS yet, you can do so by running
the following commands:
ipfs init (on initial installation)
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["localhost:4200"]' ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["localhost:4200"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST"]' ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Credentials '["true"]' ipfs config --json API.HTTPHeaders.Access-Control-Allow-Credentials '["true"]'
+11 -1
View File
@@ -9,7 +9,15 @@ export default Component.extend({
kredits: service(), kredits: service(),
attributes: null, attributes: null,
contributors: alias('kredits.contributorsSorted'),
contributors: computed('kredits.contributorsSorted.[]', function() {
return this.kredits.contributorsSorted.map(c => {
return {
id: c.id.toString(),
name: c.name
}
})
}),
isValidContributor: notEmpty('contributorId'), isValidContributor: notEmpty('contributorId'),
isValidKind: notEmpty('kind'), isValidKind: notEmpty('kind'),
@@ -57,6 +65,8 @@ export default Component.extend({
const attributes = this.getProperties(Object.keys(this.attributes)); const attributes = this.getProperties(Object.keys(this.attributes));
attributes.contributorId = parseInt(this.contributorId);
let dateInput = (attributes.date instanceof Array) ? let dateInput = (attributes.date instanceof Array) ?
attributes.date[0] : attributes.date; attributes.date[0] : attributes.date;
+1 -1
View File
@@ -4,7 +4,7 @@
<p> <p>
<select required onchange={{action (mut this.contributorId) value="target.value"}}> <select required onchange={{action (mut this.contributorId) value="target.value"}}>
<option value="" selected disabled hidden></option> <option value="" selected disabled hidden></option>
{{#each @contributors as |contributor|}} {{#each this.contributors as |contributor|}}
<option value={{contributor.id}} selected={{eq this.contributorId contributor.id}}>{{contributor.name}}</option> <option value={{contributor.id}} selected={{eq this.contributorId contributor.id}}>{{contributor.name}}</option>
{{/each}} {{/each}}
</select> </select>
@@ -15,7 +15,7 @@ export default class AddReimbursementComponent extends Component {
@alias('kredits.contributorsSorted') contributors; @alias('kredits.contributorsSorted') contributors;
@tracked contributorId = null; @tracked recipientId = null;
@tracked title = ''; @tracked title = '';
@tracked total = '0'; @tracked total = '0';
@tracked expenses = A([]); @tracked expenses = A([]);
@@ -86,7 +86,7 @@ export default class AddReimbursementComponent extends Component {
@action @action
updateContributor(event) { updateContributor(event) {
this.contributorId = event.target.value; this.recipientId = event.target.value;
} }
@action @action
@@ -115,15 +115,15 @@ export default class AddReimbursementComponent extends Component {
@action @action
submit (e) { submit (e) {
e.preventDefault(); e.preventDefault();
if (!this.kredits.currentUser) { window.alert('You need to connect your Ethereum account first.'); return false } if (!this.kredits.currentUser) { window.alert('You need to connect your RSK account first.'); return false }
if (!this.kredits.currentUserIsCore) { window.alert('Only core contributors can submit reimbursements.'); return false } if (!this.kredits.currentUserIsCore) { window.alert('Only core contributors can submit reimbursements.'); return false }
const contributor = this.contributors.findBy('id', this.contributorId); const contributor = this.contributors.findBy('id', parseInt(this.recipientId));
const attributes = { const attributes = {
amount: parseInt(parseFloat(this.total) * 100000000), // convert to sats amount: parseInt(parseFloat(this.total) * 100000000), // convert to sats
token: config.tokens['WBTC'], token: config.tokens['BTC'],
contributorId: parseInt(this.contributorId), recipientId: parseInt(this.recipientId),
title: `Expenses covered by ${contributor.name}`, title: `Expenses covered by ${contributor.name}`,
description: this.description, description: this.description,
url: this.url, url: this.url,
@@ -12,7 +12,7 @@
</label> </label>
<fieldset class="horizontal thirds total-amounts"> <fieldset class="horizontal thirds total-amounts">
<label> <label>
<p class="label">Total amount (WBTC):</p> <p class="label">Total amount (BTC):</p>
<p> <p>
<Input @type="text" <Input @type="text"
@placeholder="0.0015" @placeholder="0.0015"
+2 -2
View File
@@ -10,8 +10,8 @@
{{#each this.balances as |balance|}} {{#each this.balances as |balance|}}
<tr> <tr>
<th>{{balance.token.symbol}}</th> <th>{{balance.token.symbol}}</th>
<td class="amount">{{fmt-crypto-currency balance.balance balance.token.symbol}}</td> <td class="amount">{{balance.confirmed_balance}}</td>
<td class="fiat-amount">~{{balance.balanceUsd}} USD</td> <td class="fiat-amount">~{{balance.balanceUSD}} USD</td>
</tr> </tr>
{{/each}} {{/each}}
</tbody> </tbody>
@@ -24,10 +24,9 @@ export default Component.extend({
contributors: sort('kredits.contributors', 'contributorsSorting'), contributors: sort('kredits.contributors', 'contributorsSorting'),
contributorsActive: computed('contributors.[]', 'contributions', function() { contributorsActive: computed('contributors.[]', 'contributions', function() {
const activeIds = new Set(this.contributions.mapBy('contributorId') const activeIds = new Set(this.contributions.mapBy('contributorId'));
.map(id => id.toString()));
return this.contributors.filter(c => activeIds.has(c.id.toString())); return this.contributors.filter(c => activeIds.has(c.id));
}), }),
contributionKinds: computed('contributions.[]', function() { contributionKinds: computed('contributions.[]', function() {
@@ -42,7 +41,7 @@ export default Component.extend({
c.amount <= 500) { included = false; } c.amount <= 500) { included = false; }
if (isPresent(this.contributorId) && if (isPresent(this.contributorId) &&
c.contributorId.toString() !== this.contributorId.toString()) { included = false; } c.contributorId !== parseInt(this.contributorId)) { included = false; }
if (isPresent(this.contributionKind) && if (isPresent(this.contributionKind) &&
c.kind !== this.contributionKind) { included = false; } c.kind !== this.contributionKind) { included = false; }
@@ -8,7 +8,7 @@
</p> </p>
<p class="token-amount"> <p class="token-amount">
<span class="amount"> <span class="amount">
{{sats-to-btc reimbursement.amount}}</span>&#8239;<span class="symbol">WBTC</span> {{sats-to-btc reimbursement.amount}}</span>&#8239;<span class="symbol">BTC</span>
</p> </p>
<ul class="expense-list"> <ul class="expense-list">
{{#each reimbursement.expenses as |expense|}} {{#each reimbursement.expenses as |expense|}}
+2 -2
View File
@@ -6,10 +6,10 @@ export default helper(function fmtCryptoCurrency(params/*, hash*/) {
const code = params[1]; const code = params[1];
switch(code) { switch(code) {
case 'ETH': case 'RBTC':
fmtAmount = amount / 1000000000000000000; fmtAmount = amount / 1000000000000000000;
break; break;
case 'WBTC': case 'BTC':
fmtAmount = amount / 100000000; fmtAmount = amount / 100000000;
break; break;
} }
-2
View File
@@ -3,7 +3,6 @@ import { isEmpty, isPresent } from '@ember/utils';
import moment from 'moment'; import moment from 'moment';
export default EmberObject.extend({ export default EmberObject.extend({
// Contract // Contract
id: null, id: null,
contributorId: null, contributorId: null,
@@ -48,5 +47,4 @@ export default EmberObject.extend({
serialize () { serialize () {
return JSON.stringify(this); return JSON.stringify(this);
} }
}); });
-1
View File
@@ -22,5 +22,4 @@ export default EmberObject.extend({
serialize () { serialize () {
return JSON.stringify(this); return JSON.stringify(this);
} }
}); });
+2 -6
View File
@@ -6,19 +6,15 @@ export default Route.extend({
kredits: service(), kredits: service(),
model(params) { model(params) {
const contribution = this.kredits.contributions.findBy('id', parseInt(params.id)); return this.kredits.contributions.findBy('id', parseInt(params.id));
contribution.contributorId = contribution.contributorId.toString();
return contribution;
}, },
setupController (controller, model) { setupController (controller, model) {
this._super(controller, model); this._super(controller, model);
controller.set('attributes', model.getProperties([ controller.set('attributes', model.getProperties([
'kind', 'amount', 'description', 'url', 'details' 'contributorId', 'kind', 'amount', 'description', 'url', 'details'
])); ]));
controller.set('attributes.contributorId', model.contributorId.toString());
controller.set('attributes.date', model.jsDate); controller.set('attributes.date', model.jsDate);
} }
+17 -23
View File
@@ -1,44 +1,38 @@
import Service from '@ember/service'; import Service, { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking'; import { tracked } from '@glimmer/tracking';
import { A } from '@ember/array'; import { A } from '@ember/array';
import { task } from 'ember-concurrency-decorators'; import { task } from 'ember-concurrency-decorators';
import config from 'kredits-web/config/environment'; import config from 'kredits-web/config/environment';
const txServiceBaseUrl = `${config.gnosisSafe.txServiceHost}/api/v1/safes/${config.gnosisSafe.address}`;
export default class CommunityFundsService extends Service { export default class CommunityFundsService extends Service {
@service exchangeRates;
@tracked balancesLoaded = false; @tracked balancesLoaded = false;
@tracked balances = A([]); @tracked balances = A([]);
@task @task
*fetchBalances () { *fetchBalances () {
const uri = `${txServiceBaseUrl}/balances/usd/`; yield fetch(config.btcBalanceAPI).then(res => res.json())
.then(res => {
yield fetch(uri).then(res => res.json()) return this.processBalances(res);
.then(res => this.processBalances(res)) })
.catch(err => { .catch(err => {
console.log(`[community-funds] Fetching balances failed:`); console.log(`[community-funds] Fetching balances failed:`);
console.error(err); console.error(err);
}); });
} }
processBalances (res) { async processBalances (res) {
for (const balance of res) { await this.exchangeRates.fetchRates();
// Format and round the approximate USD value // Format and round the approximate USD value
const lang = navigator.language || navigator.userLanguage; const lang = navigator.language || navigator.userLanguage;
balance.balanceUsd = Math.round(balance.balanceUsd).toLocaleString(lang); const balanceUSD = res.confirmed_balance * this.exchangeRates.btcusd;
res.balanceUSD = Math.round(balanceUSD).toLocaleString(lang);
if (balance.token) { this.balances.pushObject({
// ERC20 token, has all meta data ...res,
this.balances.pushObject(balance); ...{ token: { name: 'BTC', symbol: 'BTC'} }
} else { });
// ETH, missing meta data
this.balances.pushObject({
...balance,
...{ token: { name: 'Ether', symbol: 'ETH'} }
});
}
}
this.balancesLoaded = true; this.balancesLoaded = true;
} }
+1 -1
View File
@@ -8,7 +8,7 @@ const bitstampBaseUrl = `${config.corsProxy}https://www.bitstamp.net/api/v2`;
async function fetchFromBitstamp(currencyPair) { async function fetchFromBitstamp(currencyPair) {
try { try {
const res = await fetch(`${bitstampBaseUrl}/ticker/${currencyPair}/`).then(r => r.json()); const res = await fetch(`${bitstampBaseUrl}/ticker/${currencyPair}/`).then(r => r.json());
return res.vwap; // Last 24 hours volume weighted average price return parseFloat(res.vwap); // Last 24 hours volume weighted average price
} catch(e) { } catch(e) {
console.error('Could not fetch exchange rate from Bitstamp:', e); console.error('Could not fetch exchange rate from Bitstamp:', e);
return 0; return 0;
+15 -13
View File
@@ -160,12 +160,12 @@ export default Service.extend({
kreditsByContributor: computed('contributionsUnconfirmed.@each.vetoed', 'contributors.[]', function() { kreditsByContributor: computed('contributionsUnconfirmed.@each.vetoed', 'contributors.[]', function() {
const contributionsUnconfirmed = this.contributionsUnconfirmed.filterBy('vetoed', false); const contributionsUnconfirmed = this.contributionsUnconfirmed.filterBy('vetoed', false);
const contributionsGrouped = groupBy(contributionsUnconfirmed, 'contributorId'); const contributionsGrouped = groupBy(contributionsUnconfirmed, 'contributorId');
const contributorsWithUnconfirmed = contributionsGrouped.map(c => c.value.toString()); const contributorsWithUnconfirmed = contributionsGrouped.map(c => c.value);
const contributorsWithOnlyConfirmed = this.contributors.reject(c => contributorsWithUnconfirmed.includes(c.id)) const contributorsWithOnlyConfirmed = this.contributors.reject(c => contributorsWithUnconfirmed.includes(c.id))
const kreditsByContributor = contributionsGrouped.map(c => { const kreditsByContributor = contributionsGrouped.map(c => {
const amountUnconfirmed = c.items.mapBy('amount').reduce((a, b) => a + b); const amountUnconfirmed = c.items.mapBy('amount').reduce((a, b) => a + b);
const contributor = this.contributors.findBy('id', c.value.toString()); const contributor = this.contributors.findBy('id', c.value);
return EmberObject.create({ return EmberObject.create({
contributor: contributor, contributor: contributor,
@@ -275,7 +275,7 @@ export default Service.extend({
}); });
}, },
loadContributorFromData(data) { loadContributorFromData (data) {
const contributor = Contributor.create(processContributorData(data)); const contributor = Contributor.create(processContributorData(data));
const loadedContributor = this.contributors.findBy('id', contributor.id); const loadedContributor = this.contributors.findBy('id', contributor.id);
if (loadedContributor) { this.contributors.removeObject(loadedContributor); } if (loadedContributor) { this.contributors.removeObject(loadedContributor); }
@@ -285,7 +285,7 @@ export default Service.extend({
async cacheLoadedContributors () { async cacheLoadedContributors () {
for (const c of this.contributors) { for (const c of this.contributors) {
await this.browserCache.contributors.setItem(c.id, c.serialize()); await this.browserCache.contributors.setItem(c.id.toString(), c.serialize());
} }
console.debug(`[kredits] Cached ${this.contributors.length} contributors in browser storage`); console.debug(`[kredits] Cached ${this.contributors.length} contributors in browser storage`);
return Promise.resolve(); return Promise.resolve();
@@ -340,7 +340,7 @@ export default Service.extend({
loadContributionFromData(data) { loadContributionFromData(data) {
const contribution = Contribution.create(processContributionData(data)); const contribution = Contribution.create(processContributionData(data));
contribution.set('contributor', this.contributors.findBy('id', data.contributorId.toString())); contribution.set('contributor', this.contributors.findBy('id', data.contributorId));
const loadedContribution = this.contributions.findBy('id', contribution.id); const loadedContribution = this.contributions.findBy('id', contribution.id);
if (loadedContribution) { this.contributions.removeObject(loadedContribution); } if (loadedContribution) { this.contributions.removeObject(loadedContribution); }
this.contributions.pushObject(contribution); this.contributions.pushObject(contribution);
@@ -349,7 +349,7 @@ export default Service.extend({
async cacheLoadedContributions () { async cacheLoadedContributions () {
for (const c of this.contributions) { for (const c of this.contributions) {
await this.browserCache.contributions.setItem(c.id, c.serialize()); await this.browserCache.contributions.setItem(c.id.toString(), c.serialize());
} }
console.debug(`[kredits] Cached ${this.contributions.length} contributions in browser storage`); console.debug(`[kredits] Cached ${this.contributions.length} contributions in browser storage`);
return Promise.resolve(); return Promise.resolve();
@@ -575,7 +575,7 @@ export default Service.extend({
loadReimbursementFromData(data) { loadReimbursementFromData(data) {
const obj = Reimbursement.create(processReimbursementData(data)); const obj = Reimbursement.create(processReimbursementData(data));
obj.set('contributor', this.contributors.findBy('id', data.contributorId.toString())); obj.set('contributor', this.contributors.findBy('id', data.recipientId));
this.removeObjectFromCollectionIfLoaded('reimbursements', obj.id); this.removeObjectFromCollectionIfLoaded('reimbursements', obj.id);
this.reimbursements.pushObject(obj); this.reimbursements.pushObject(obj);
return obj; return obj;
@@ -589,7 +589,7 @@ export default Service.extend({
console.debug('[kredits] add reimbursement response', data); console.debug('[kredits] add reimbursement response', data);
const reimbursement = Reimbursement.create(attributes); const reimbursement = Reimbursement.create(attributes);
reimbursement.setProperties({ reimbursement.setProperties({
contributor: this.contributors.findBy('id', attributes.contributorId.toString()), contributor: this.contributors.findBy('id', attributes.recipientId),
pendingTx: data, pendingTx: data,
confirmedAt: this.currentBlock + 40320 confirmedAt: this.currentBlock + 40320
}); });
@@ -645,13 +645,15 @@ export default Service.extend({
const contributorData = await this.kredits.Contributor.getById(contributorId); const contributorData = await this.kredits.Contributor.getById(contributorId);
const newContributor = Contributor.create(contributorData); const newContributor = Contributor.create(contributorData);
const oldContributor = this.contributors.findBy('id', contributorId.toString()); // TODO check for actual differences in the contributor data first
const oldContributor = this.contributors.findBy('id', contributorId);
if (oldContributor) { if (oldContributor) {
console.debug('[kredits] old contributor', oldContributor); // console.debug('[kredits] cached contributor', oldContributor);
this.contributors.removeObject(oldContributor); this.contributors.removeObject(oldContributor);
} }
console.debug('[kredits] new contributor', newContributor); // console.debug('[kredits] incoming contributor data', newContributor);
this.contributors.pushObject(newContributor); this.contributors.pushObject(newContributor);
}, },
@@ -660,13 +662,13 @@ export default Service.extend({
const pendingContribution = this.contributions.find(c => { const pendingContribution = this.contributions.find(c => {
return (c.id === null) && return (c.id === null) &&
(c.contributorId.toString() === contributorId.toString()) && (c.contributorId === contributorId) &&
(c.amount.toString() === amount.toString()); (c.amount.toString() === amount.toString());
}); });
if (pendingContribution) { if (pendingContribution) {
const attributes = await this.kredits.Contribution.getById(id); const attributes = await this.kredits.Contribution.getById(id);
attributes.contributor = this.contributors.findBy('id', attributes.contributorId.toString()); attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
const newContribution = Contribution.create(attributes); const newContribution = Contribution.create(attributes);
this.contributions.addObject(newContribution); this.contributions.addObject(newContribution);
this.contributions.removeObject(pendingContribution); this.contributions.removeObject(pendingContribution);
+3 -2
View File
@@ -21,15 +21,16 @@ section#funds {
} }
th { th {
font-size: 1.5rem;
text-align: left; text-align: left;
padding-right: 1.2rem; padding-right: 1rem;
} }
td { td {
text-align: right; text-align: right;
&.amount { &.amount {
font-size: 1.5rem; font-size: 2rem;
padding-right: 1.2rem; padding-right: 1.2rem;
} }
+2 -3
View File
@@ -8,9 +8,8 @@ export default function processContributionData(data) {
} }
const otherProperties = [ const otherProperties = [
'id', 'contributorId', 'amount', 'vetoed', 'id', 'contributorId', 'amount', 'vetoed', 'ipfsHash', 'kind',
'ipfsHash', 'kind', 'description', 'details', 'description', 'details', 'url', 'date', 'time', 'pendingTx'
'url', 'date', 'time', 'pendingTx'
]; ];
otherProperties.forEach(prop => { otherProperties.forEach(prop => {
+1 -2
View File
@@ -1,13 +1,12 @@
export default function processContributorData(data) { export default function processContributorData(data) {
const processed = { const processed = {
id: data.id.toString(),
balance: data.balanceInt, balance: data.balanceInt,
totalKreditsEarned: data.totalKreditsEarned, totalKreditsEarned: data.totalKreditsEarned,
contributionsCount: data.contributionsCount?.toNumber() contributionsCount: data.contributionsCount?.toNumber()
} }
const otherProperties = [ const otherProperties = [
'account', 'accounts', 'ipfsHash', 'isCore', 'kind', 'name', 'url', 'id', 'account', 'accounts', 'ipfsHash', 'isCore', 'kind', 'name', 'url',
'github_username', 'github_uid', 'wiki_username', 'zoom_display_name' 'github_username', 'github_uid', 'wiki_username', 'zoom_display_name'
]; ];
+1 -1
View File
@@ -10,7 +10,7 @@ export default function processReimbursementData(data) {
} }
const otherProperties = [ const otherProperties = [
'id', 'contributorId', 'token', 'vetoed', 'ipfsHash', 'id', 'recipientId', 'token', 'vetoed', 'ipfsHash',
'expenses', 'pendingTx' 'expenses', 'pendingTx'
]; ];
+4 -7
View File
@@ -39,13 +39,12 @@ module.exports = function(environment) {
}, },
tokens: { tokens: {
'WBTC': '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599' // TODO this is still the WBTC address, since contracts currently
// requires a token address for reimbursements
'BTC': '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599'
}, },
gnosisSafe: { btcBalanceAPI: 'https://api.kosmos.org/kredits/onchain_btc_balance',
txServiceHost: 'https://safe-transaction.mainnet.gnosis.io',
address: '0x9CC29b8373FF92B01C1f09F31B5DD862350c167E'
},
corsProxy: 'https://cors.5apps.com/?uri=' corsProxy: 'https://cors.5apps.com/?uri='
}; };
@@ -67,8 +66,6 @@ module.exports = function(environment) {
protocol: 'http', protocol: 'http',
gatewayUrl: 'http://localhost:8080/ipfs' gatewayUrl: 'http://localhost:8080/ipfs'
}; };
ENV.corsProxy = 'https://cors-anywhere.herokuapp.com/';
} }
if (environment === 'test') { if (environment === 'test') {
+1 -1
View File
@@ -18,7 +18,7 @@ const data = [
data.forEach(attrs => { data.forEach(attrs => {
const c = Model.create(processContributionData(attrs)); const c = Model.create(processContributionData(attrs));
c.set('contributor', contributors.findBy('id', attrs.contributorId.toString())); c.set('contributor', contributors.findBy('id', attrs.contributorId));
items.push(c); items.push(c);
}); });
+3 -3
View File
@@ -4,9 +4,9 @@ import processContributorData from 'kredits-web/utils/process-contributor-data';
const contributors = []; const contributors = [];
const data = [ const data = [
{ id: '1', name: 'Bumi', totalKreditsEarned: 11500, github_uid: 318 }, { id: 1, name: 'Bumi', totalKreditsEarned: 11500, github_uid: 318 },
{ id: '2', name: 'Râu Cao', totalKreditsEarned: 3000, github_uid: 842 }, { id: 2, name: 'Râu Cao', totalKreditsEarned: 3000, github_uid: 842 },
{ id: '3', name: 'Manuel', totalKreditsEarned: 0, github_uid: 54812 } { id: 3, name: 'Manuel', totalKreditsEarned: 0, github_uid: 54812 }
]; ];
data.forEach(attrs => { data.forEach(attrs => {
@@ -16,8 +16,10 @@ module('Integration | Component | contribution-list', function(hooks) {
}); });
test('it renders filtered contributions', async function(assert) { test('it renders filtered contributions', async function(assert) {
let service = this.owner.lookup('service:kredits'); let kredits = this.owner.lookup('service:kredits');
service.set('contributors', contributors); kredits.set('contributors', contributors);
debugger;
this.set('fixtures', contributions); this.set('fixtures', contributions);
await render(hbs`{{contribution-list contributions=fixtures showQuickFilter=true}}`); await render(hbs`{{contribution-list contributions=fixtures showQuickFilter=true}}`);
@@ -8,14 +8,14 @@ module('Integration | Component | user-avatar', function(hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
test('it renders', async function(assert) { test('it renders', async function(assert) {
this.set('bumi', contributors.findBy('id', '1')); this.set('bumi', contributors.findBy('id', 1));
await render(hbs`{{user-avatar contributor=bumi}}`); await render(hbs`{{user-avatar contributor=bumi}}`);
assert.dom(this.element).hasText(''); assert.dom(this.element).hasText('');
}); });
test('default image source URL', async function(assert) { test('default image source URL', async function(assert) {
this.set('bumi', contributors.findBy('id', '1')); this.set('bumi', contributors.findBy('id', 1));
await render(hbs`{{user-avatar contributor=bumi}}`); await render(hbs`{{user-avatar contributor=bumi}}`);
assert.equal(this.element.querySelector('img').src, assert.equal(this.element.querySelector('img').src,
@@ -23,7 +23,7 @@ module('Integration | Component | user-avatar', function(hooks) {
}); });
test('size-specific image source URLs', async function(assert) { test('size-specific image source URLs', async function(assert) {
this.set('bumi', contributors.findBy('id', '1')); this.set('bumi', contributors.findBy('id', 1));
this.set('size', 'medium'); this.set('size', 'medium');
await render(hbs`{{user-avatar contributor=bumi size=size}}`); await render(hbs`{{user-avatar contributor=bumi size=size}}`);
@@ -6,15 +6,15 @@ import { hbs } from 'ember-cli-htmlbars';
module('Integration | Helper | fmt-crypto-currency', function(hooks) { module('Integration | Helper | fmt-crypto-currency', function(hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
test('it converts Wei to ETH', async function(assert) { test('it converts Wei to RBTC', async function(assert) {
this.set('balanceETH', '500000000000000000'); this.set('balanceRBTC', '500000000000000000');
await render(hbs`{{fmt-crypto-currency balanceETH "ETH"}}`); await render(hbs`{{fmt-crypto-currency balanceRBTC "RBTC"}}`);
assert.equal(this.element.textContent.trim(), '0.5'); assert.equal(this.element.textContent.trim(), '0.5');
}); });
test('it converts Satoshis to (W)BTC', async function(assert) { test('it converts Satoshis to BTC', async function(assert) {
this.set('balanceWBTC', '117214976'); this.set('balanceBTC', '117214976');
await render(hbs`{{fmt-crypto-currency balanceWBTC "WBTC"}}`); await render(hbs`{{fmt-crypto-currency balanceBTC "BTC"}}`);
assert.equal(this.element.textContent.trim(), '1.17214976'); assert.equal(this.element.textContent.trim(), '1.17214976');
}); });
}); });
@@ -8,7 +8,7 @@ module('Unit | Utility | process-contributor-data', function() {
test('formats the data correctly', function(assert) { test('formats the data correctly', function(assert) {
// TODO use integers everywhere for IDs // TODO use integers everywhere for IDs
assert.ok(typeof result.id === 'string'); assert.ok(typeof result.id === 'number');
assert.ok(typeof result.balance === 'number'); assert.ok(typeof result.balance === 'number');
assert.ok(typeof result.totalKreditsEarned === 'number'); assert.ok(typeof result.totalKreditsEarned === 'number');
assert.ok(typeof result.contributionsCount === 'number'); assert.ok(typeof result.contributionsCount === 'number');