Compare commits

..

1 Commits

Author SHA1 Message Date
bumi ece573ab3c load kredits contract definition from kredits-contracts package 2017-02-05 21:48:18 +08:00
19 changed files with 98 additions and 362 deletions
+12 -47
View File
@@ -5,64 +5,29 @@ export default Ember.Component.extend({
id: null,
realName: null,
address: null,
ipfsHash: null,
isCore: true,
inProgress: false,
isValidId: function() {
return Ember.isPresent(this.get('id'));
classId: function() {
let value = this.get('id');
return (Ember.isEmpty(value)) ? null : 'valid';
}.property('id'),
isValidRealName: function() {
return Ember.isPresent(this.get('realName'));
classRealName: function() {
let value = this.get('realName');
return (Ember.isEmpty(value)) ? null : 'valid';
}.property('realName'),
isValidAddress: function() {
return this.get('kredits.web3Instance').isAddress(this.get('address'));
classAddress: function() {
let value = this.get('address');
return (Ember.isEmpty(value)) ? null : 'valid';
}.property('address'),
isValid: function() {
return this.get('isValidId') && this.get('isValidRealName') && this.get('isValidAddress');
}.property('isValidAddress', 'isValidId', 'isValidRealName'),
reset: function() {
this.setProperties({
id: null,
realName: null,
address: null,
ipfsHash: null,
isCore: true,
inProgress: false
});
},
actions: {
save() {
if (!this.get('contractInteractionEnabled')) {
alert('Only core team members can add new contributors. Please ask someone to set you up.');
return;
}
if (this.get('isValid')) {
this.set('inProgress', true);
this.get('kredits').addContributor(
this.get('address'),
this.get('realName'),
'', // TODO: this.get('ipfsHash')
this.get('isCore'),
this.get('id')
).then(contributor => {
this.reset();
this.get('contributors').pushObject(contributor);
window.scroll(0,0);
});
} else {
alert('Invalid data. Please review and try again.');
}
console.log('id', this.get('id'));
console.log('realName', this.get('realName'));
console.log('address', this.get('address'));
}
}
+4 -4
View File
@@ -4,23 +4,23 @@
type="text"
placeholder="GitHub UID (123)"
value=id
class=(if isValidId 'valid' '')}}
class=classId}}
</p>
<p>
{{input name="realname"
type="text"
placeholder="Carl Sagan"
value=realName
class=(if isValidRealName 'valid' '')}}
class=classRealName}}
</p>
<p>
{{input name="address"
type="text"
placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4"
value=address
class=(if isValidAddress 'valid' '')}}
class=classAddress}}
</p>
<p class="actions">
{{input type="submit" value=(if inProgress 'Processing' 'Save') disabled=inProgress}}
<input type="submit" value="Save">
</p>
</form>
+1 -1
View File
@@ -1,6 +1,6 @@
<tbody>
{{#each contributors as |contributor|}}
<tr class="{{if contributor.isCurrentUser 'current-user'}}">
<tr>
<td class="person">
<img class="avatar" src={{contributor.avatarURL}}>
{{contributor.github_username}}
+1 -5
View File
@@ -8,11 +8,7 @@ export default Ember.Component.extend({
actions: {
confirm(proposalId) {
if (this.get('contractInteractionEnabled')) {
this.sendAction('confirmAction', proposalId);
} else {
window.alert('Only members can vote on proposals. Please ask someone to set you up.');
}
this.sendAction('confirmAction', proposalId);
}
}
+4 -88
View File
@@ -1,5 +1,4 @@
import Ember from 'ember';
import Proposal from 'kredits-web/models/proposal';
const {
computed,
@@ -23,21 +22,21 @@ export default Ember.Controller.extend({
let proposals = this.get('model.proposals')
.filterBy('executed', false)
.map(p => {
p.set('recipientName', this.findContributorByAddress(p.get('recipientAddress')).github_username);
p.recipientName = this.findContributorByAddress(p.recipientAddress).github_username;
return p;
});
return proposals;
}.property('model.proposals.[]', 'model.proposals.@each.executed', 'model.contributors.[]'),
}.property('model.proposals.[]', 'model.contributors.[]'),
proposalsClosed: function() {
let proposals = this.get('model.proposals')
.filterBy('executed', true)
.map(p => {
p.set('recipientName', this.findContributorByAddress(p.get('recipientAddress')).github_username);
p.recipientName = this.findContributorByAddress(p.recipientAddress).github_username;
return p;
});
return proposals;
}.property('model.proposals.[]', 'model.proposals.@each.executed', 'model.contributors.[]'),
}.property('model.proposals.[]', 'model.contributors.[]'),
proposalsSorting: ['id:desc'],
proposalsClosedSorted: Ember.computed.sort('proposalsClosed', 'proposalsSorting'),
@@ -46,89 +45,6 @@ export default Ember.Controller.extend({
contributorsSorting: ['kredits:desc'],
contributorsSorted: Ember.computed.sort('model.contributors', 'contributorsSorting'),
watchContractEvents: function() {
let events = this.get('kredits.kreditsContract')
.allEvents(/* [additionalFilterObject], */);
events.watch((error, data) => {
Ember.Logger.debug('[index] Received contract event', data);
switch (data.event) {
case 'ProposalCreated':
this._handleProposalCreated(data);
break;
case 'ProposalExecuted':
this._handleProposalExecuted(data);
break;
case 'ProposalVoted':
this._handleProposalVoted(data);
break;
case 'Transfer':
this._handleTransfer(data);
break;
}
});
}.on('init'),
_handleProposalCreated(data) {
if (Ember.isPresent(this.get('model.proposals')
.findBy('id', data.args.id.toNumber()))) {
Ember.Logger.debug('[index] proposal exists, not adding from event');
return false;
}
let proposal = Proposal.create({
id: data.args.id.toNumber(),
creatorAddress: data.args.creator,
recipientAddress: data.args.recipient,
recipientName: null,
votesCount: 0,
votesNeeded: 2,
amount: data.args.amount.toNumber(),
executed: false,
url: data.args.url,
ipfsHash: data.args.ipfsHash
});
this.get('model.proposals').pushObject(proposal);
},
_handleProposalExecuted(data) {
if (this.get('model.proposals')
.findBy('id', data.args.id.toNumber())
.get('executed')) {
Ember.Logger.debug('[index] proposal already executed, not adding from event');
return false;
}
this.get('model.proposals')
.findBy('id', data.args.id.toNumber())
.setProperties({
'executed': true,
'votesCount': 2 // TODO use real count
});
this.get('model.contributors')
.findBy('address', data.args.recipient)
.incrementProperty('kredits', data.args.amount.toNumber());
},
_handleProposalVoted(data) {
this.get('model.proposals')
.findBy('id', data.args.id.toNumber())
.incrementProperty('votesCount', 1);
},
_handleTransfer(data) {
this.get('model.contributors')
.findBy('address', data.args.from)
.incrementProperty('kredits', - data.args.value.toNumber());
this.get('model.contributors')
.findBy('address', data.args.to)
.incrementProperty('kredits', data.args.value.toNumber());
},
actions: {
confirmProposal(proposalId) {
+1 -1
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Kredits</title>
<title>KreditsWeb</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+1 -3
View File
@@ -2,12 +2,10 @@ import Ember from 'ember';
export default Ember.Object.extend({
address: null,
github_username: null,
github_uid: null,
ipfsHash: null,
kredits: null,
isCurrentUser: false,
address: null,
avatarURL: function() {
return `https\:\/\/avatars2.githubusercontent.com/u/${this.get('github_uid')}?v=3&s=128`;
+2 -3
View File
@@ -3,9 +3,8 @@ import Ember from 'ember';
export default Ember.Object.extend({
id: null,
creatorAddress: null,
recipientAddress: null,
recipientName: null,
creator: null,
recipient: null,
votesCount: null,
votesNeeded: null,
amount: null,
-31
View File
@@ -1,31 +0,0 @@
import Ember from 'ember';
import ipfsAPI from 'npm:ipfs-api';
import config from 'kredits-web/config/environment';
export default Ember.Service.extend({
ipfsInstance: null,
ipfs: function() {
if (this.get('ipfsInstance')) {
return this.get('ipfsInstance');
}
let ipfs = ipfsAPI(config.ipfs);
this.set('ipfsInstance', ipfs);
return ipfs;
}.property('ipfsInstance'),
storeFile(content) {
let ipfs = this.get('ipfs');
return ipfs.add(new ipfs.Buffer(content)).then(res => {
return res[0].hash;
});
},
getFile(hash) {
return this.get('ipfs').cat(hash, { buffer: true }).then(res => {
return res.toString();
});
}
});
+3 -29
View File
@@ -7,8 +7,6 @@ import kreditsContracts from 'npm:kredits-contracts';
export default Ember.Service.extend({
ipfs: Ember.inject.service(),
web3Instance: null,
web3Provided: false, // Web3 provided (using Mist Browser, Metamask et al.)
@@ -35,18 +33,14 @@ export default Ember.Service.extend({
return web3Instance;
}.property('web3Instance'),
currentUserAccounts: function() {
return (this.get('web3Provided') && this.get('web3').eth.accounts) || [];
}.property('web3', 'web3Provided'),
kreditsContract: function() {
if (this.get('kreditsContractInstance')) {
return this.get('kreditsContractInstance');
}
console.log(config.ethereumChain);
let contract = kreditsContracts(this.get('web3'), config.ethereumChain)['Kredits'];
let contract = kreditsContracts(this.get('web3'))['Kredits'];
window.Kredits = contract;
this.set('kreditsContractInstance', contract);
return contract;
}.property('web3'),
@@ -70,8 +64,7 @@ export default Ember.Service.extend({
github_username: person[1],
github_uid: person[0],
ipfsHash: person[3],
kredits: balance.toNumber(),
isCurrentUser: this.get('currentUserAccounts').includes(address)
kredits: balance.toNumber()
});
Ember.Logger.debug('[kredits] contributor', contributor);
resolve(contributor);
@@ -138,25 +131,6 @@ export default Ember.Service.extend({
});
},
addContributor(address, name, ipfsHash, isCore, id) {
Ember.Logger.debug('[kredits] add contributor', name, address);
return new Ember.RSVP.Promise((resolve, reject) => {
this.get('kreditsContract').addContributor(address, name, ipfsHash, isCore, id, (err, data) => {
if (err) { reject(err); }
Ember.Logger.debug('[kredits] add contributor response', data);
let contributor = Contributor.create({
address: address,
github_username: name,
github_uid: id,
ipfsHash: ipfsHash,
kredits: 0,
isCurrentUser: this.get('currentUserAccounts').includes(address)
});
resolve(contributor);
});
});
},
logKreditsContract: function() {
Ember.Logger.debug('[kredits] kreditsContract', this.get('kreditsContract'));
}.on('init')
@@ -26,9 +26,6 @@ section#add-contributor {
input[type=submit] {
padding: 0.6rem 2rem;
&:disabled {
background-color: transparent;
}
}
}
+22 -29
View File
@@ -7,39 +7,32 @@ table.contributor-list {
&:first-of-type {
border-top: 1px solid rgba(255,255,255,0.2);
}
}
td {
padding: 0 1.2rem;
line-height: 4.2rem;
td {
padding: 0 1.2rem;
line-height: 4.2rem;
background-color: rgba(255,255,255,0.1);
&.person {
text-align: left;
font-size: 1.4rem;
img.avatar {
width: 2rem;
height: 2rem;
vertical-align: middle;
margin-right: 0.2rem;
border-radius: 1rem;
}
}
&.kredits {
text-align: right;
.amount {
font-size: 1.4rem;
}
.symbol {
font-size: 1rem;
padding-left: 0.2rem;
}
background-color: rgba(255,255,255,0.1);
&.person {
text-align: left;
font-size: 1.4rem;
img.avatar {
width: 2rem;
height: 2rem;
vertical-align: middle;
margin-right: 0.2rem;
border-radius: 1rem;
}
}
&.current-user {
td {
background-color: rgba(255,255,255,0.2);
&.kredits {
text-align: right;
.amount {
font-size: 1.4rem;
}
.symbol {
font-size: 1rem;
padding-left: 0.2rem;
}
}
}
+25 -28
View File
@@ -13,37 +13,34 @@
</div>
</section>
{{#if proposalsOpen}}
<section id="proposals-open">
{{#if contractInteractionEnabled}}
{{#if proposalsOpen}}
<section id="proposals-open">
<header>
<h2>Open Proposals</h2>
</header>
<div class="content">
{{proposal-list proposals=proposalsOpenSorted confirmAction="confirmProposal"}}
</div>
</section>
{{/if}}
<section id="proposals-closed">
<header>
<h2>Open Proposals</h2>
<h2>Closed Proposals</h2>
</header>
<div class="content">
{{proposal-list proposals=proposalsOpenSorted
confirmAction="confirmProposal"
contractInteractionEnabled=contractInteractionEnabled}}
{{proposal-list proposals=proposalsClosedSorted confirmAction="confirmProposal"}}
</div>
</section>
<section id="add-contributor">
<header>
<h2>Add Contributor</h2>
</header>
<div class="content">
{{add-contributor kredits=kredits}}
</div>
</section>
{{/if}}
<section id="proposals-closed">
<header>
<h2>Closed Proposals</h2>
</header>
<div class="content">
{{proposal-list proposals=proposalsClosedSorted
confirmAction="confirmProposal"}}
</div>
</section>
<section id="add-contributor">
<header>
<h2>Add Contributor</h2>
</header>
<div class="content">
{{add-contributor kredits=kredits
contributors=model.contributors
contractInteractionEnabled=contractInteractionEnabled}}
</div>
</section>
+1 -20
View File
@@ -19,33 +19,16 @@ module.exports = function(environment) {
APP: {
// Here you can pass flags/options to your application instance
// when it is created
},
browserify: {
transform: [
["babelify", {
presets: ["es2015"],
global: true
}]
]
},
web3ProviderUrl: "https://parity.kosmos.org:8545",
ethereumChain: "testnet",
ipfs: {
host: 'localhost',
port: '5001',
protocol: 'http'
}
};
if (environment === 'development') {
ENV.web3ProviderUrl = "http://139.59.248.169:8545";
// ENV.APP.LOG_RESOLVER = true;
// ENV.APP.LOG_ACTIVE_GENERATION = true;
// ENV.APP.LOG_TRANSITIONS = true;
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
// ENV.APP.LOG_VIEW_LOOKUPS = true;
ENV.ethereumChain = 'dev';
}
if (environment === 'test') {
@@ -60,8 +43,6 @@ module.exports = function(environment) {
}
if (environment === 'production') {
ENV.ethereumChain = 'testnet';
ENV.web3ProviderUrl = 'https://ropsten.infura.io';
}
return ENV;
+5 -12
View File
@@ -1,6 +1,6 @@
{
"name": "kredits-web",
"version": "0.1.0",
"version": "0.0.0",
"description": "Small description for kredits-web goes here",
"license": "MIT",
"author": "",
@@ -10,17 +10,11 @@
},
"repository": "",
"scripts": {
"start": "ember server",
"test": "ember test",
"postinstall": "bower install",
"build": "ember build",
"build-prod": "ember build --environment production",
"update-version-file": "bash scripts/update-version-file.sh",
"deploy": "npm run build-prod && npm run update-version-file && bash scripts/deploy.sh"
"start": "ember server",
"test": "ember test"
},
"devDependencies": {
"babel-preset-es2015": "^6.22.0",
"babelify": "^7.3.0",
"broccoli-asset-rev": "^2.4.5",
"ember-ajax": "^2.4.1",
"ember-browserify": "^1.1.13",
@@ -41,10 +35,9 @@
"ember-export-application-global": "^1.0.5",
"ember-load-initializers": "^0.5.1",
"ember-resolver": "^2.0.3",
"ipfs-api": "^12.1.7",
"kredits-contracts": "67P/kredits-contracts",
"loader.js": "^4.0.10",
"web3": "^0.18.2"
"web3": "^0.18.2",
"kredits-contracts": "67P/kredits-contracts"
},
"engines": {
"node": ">= 0.12.0"
-20
View File
@@ -1,20 +0,0 @@
#!/bin/sh
set -xe
# Get revision from local master
rev=`git rev-parse HEAD`
short_rev=${rev:0:7}
# Check out build branch
git checkout build-production
# Copy from build dir to root
cp -r dist/* .
# Add all files
git add --all
# Commit build files
git commit -m "Build production from $short_rev"
# Push to remote
git push 5apps build-production:master
# Push build branch to collab repo
git push origin build-production:build-production
# Go back to previous branch
git checkout -
-10
View File
@@ -1,10 +0,0 @@
#!/bin/bash
PACKAGE_VERSION=$(cat package.json \
| grep version \
| head -1 \
| awk -F: '{ print $2 }' \
| sed 's/[",]//g' \
| tr -d '[[:space:]]')
echo $PACKAGE_VERSION > dist/VERSION
@@ -1,16 +1,16 @@
// import { moduleForComponent, test } from 'ember-qunit';
// import hbs from 'htmlbars-inline-precompile';
//
// moduleForComponent('add-contributor', 'Integration | Component | add contributor', {
// integration: true
// });
//
// test('it renders', function(assert) {
//
// // Set any properties with this.set('myProperty', 'value');
// // Handle any actions with this.on('myAction', function(val) { ... });
//
// this.render(hbs`{{add-contributor}}`);
//
// assert.equal(this.$().text().trim(), '');
// });
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('add-contributor', 'Integration | Component | add contributor', {
integration: true
});
test('it renders', function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });
this.render(hbs`{{add-contributor}}`);
assert.equal(this.$().text().trim(), '');
});
-12
View File
@@ -1,12 +0,0 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('service:ipfs', 'Unit | Service | ipfs', {
// Specify the other units that are required for this test.
// needs: ['service:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let service = this.subject();
assert.ok(service);
});