Merge pull request #41 from 67P/refactor/cleanup-models

Cleanup controller, templates and service
This commit was merged in pull request #41.
This commit is contained in:
2018-04-08 12:56:05 +00:00
committed by GitHub
6 changed files with 99 additions and 121 deletions
+4 -2
View File
@@ -2,9 +2,11 @@
<li data-proposal-id={{proposal.id}} title="({{proposal.kind}}) {{proposal.description}}"> <li data-proposal-id={{proposal.id}} title="({{proposal.kind}}) {{proposal.description}}">
<span class="category {{proposal.kind}}">♥</span> <span class="category {{proposal.kind}}">♥</span>
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span> <span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
for <span class="recipient">{{proposal.recipientName}}</span> for <span class="recipient">{{proposal.contributor.name}}</span>
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span> <span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
{{#unless proposal.executed}}<button {{action "confirm" proposal.id}}>+1</button>{{/unless}} {{#unless proposal.isExecuted}}
<button {{action "confirm" proposal.id}}>+1</button>
{{/unless}}
</li> </li>
{{/each}} {{/each}}
+59 -84
View File
@@ -1,51 +1,10 @@
import Ember from 'ember'; import Ember from 'ember';
import Proposal from 'kredits-web/models/proposal'; import Controller from 'ember-controller';
import computed, { alias, filter, filterBy, sort } from 'ember-computed';
import injectService from 'ember-service/inject';
const { export default Controller.extend({
computed, kredits: injectService(),
inject: {
service
}
} = Ember;
export default Ember.Controller.extend({
kredits: service(),
contractInteractionEnabled: computed.alias('kredits.hasAccounts'),
proposalsOpen: function() {
let proposals = this.get('model.proposals')
.filterBy('executed', false)
.map(p => {
p.set('recipientName', this.get('model.contributors').findBy('id', p.get('recipientId')).name);
return p;
});
return proposals;
}.property('model.proposals.[]', 'model.proposals.@each.executed', 'model.contributors.[]'),
proposalsClosed: function() {
let proposals = this.get('model.proposals')
.filterBy('executed', true)
.map(p => {
p.set('recipientName', this.get('model.contributors').findBy('id', p.get('recipientId')).name);
return p;
});
return proposals;
}.property('model.proposals.[]', 'model.proposals.@each.executed', 'model.contributors.[]'),
proposalsSorting: ['id:desc'],
proposalsClosedSorted: Ember.computed.sort('proposalsClosed', 'proposalsSorting'),
proposalsOpenSorted: Ember.computed.sort('proposalsOpen', 'proposalsSorting'),
contributorsWithKredits: function() {
return this.get('model.contributors').filter(c => {
return c.get('balance') !== 0;
});
}.property('model.contributors.@each.balance'),
contributorsSorting: ['balance:desc'],
contributorsSorted: Ember.computed.sort('contributorsWithKredits', 'contributorsSorting'),
init() { init() {
this._super(...arguments); this._super(...arguments);
@@ -58,60 +17,76 @@ export default Ember.Controller.extend({
}); });
}, },
_handleProposalCreated(proposalId, creatorAddress, recipientAddress, amount) { contributors: alias('model.contributors'),
if (Ember.isPresent(this.get('model.proposals') contributorsWithKredits: filter('contributors', function(contributor) {
.findBy('id', proposalId.toNumber()))) { return contributor.get('balance') !== 0;
}),
contributorsSorting: ['balance:desc'],
contributorsSorted: sort('contributorsWithKredits', 'contributorsSorting'),
proposals: computed('model.proposals.[]', 'contributors.[]', function() {
return this.get('model.proposals')
.map((proposal) => {
let contributor = this.get('contributors')
.findBy('id', proposal.get('recipientId'));
proposal.set('contributor', contributor);
return proposal;
});
}),
proposalsOpen: filterBy('proposals', 'isExecuted', false),
proposalsClosed: filterBy('proposals', 'isExecuted', true),
proposalsSorting: ['id:desc'],
proposalsClosedSorted: sort('proposalsClosed', 'proposalsSorting'),
proposalsOpenSorted: sort('proposalsOpen', 'proposalsSorting'),
_handleProposalCreated(proposalId) {
// TODO: check if proposalId is already a string
let proposal = this.get('proposals')
.findBy('id', proposalId.toString());
if (proposal) {
Ember.Logger.debug('[index] proposal exists, not adding from event'); Ember.Logger.debug('[index] proposal exists, not adding from event');
return false; return;
} }
let proposal = Proposal.create({ proposal = this.get('kredits').getProposalById(proposalId);
id: proposalId.toNumber(), this.get('proposals').pushObject(proposal);
creatorAddress: creatorAddress,
recipientAddress: recipientAddress,
recipientName: null,
votesCount: 0,
votesNeeded: 2,
amount: amount.toNumber(),
executed: false
});
this.get('model.proposals').pushObject(proposal);
}, },
_handleProposalExecuted(proposalId, recipientId, amount) { _handleProposalExecuted(proposalId, recipientId, amount) {
if (this.get('model.proposals') // TODO: check if proposalId is already a string
.findBy('id', recipientId.toNumber()) let proposal = this.get('proposals')
.get('executed')) { .findBy('id', proposalId.toString());
if (proposal.get('isExecuted')) {
Ember.Logger.debug('[index] proposal already executed, not adding from event'); Ember.Logger.debug('[index] proposal already executed, not adding from event');
return false; return;
} }
this.get('model.proposals') proposal.setProperties({
.findBy('id', recipientId.toNumber()) 'executed': true,
.setProperties({ });
'executed': true,
'votesCount': 2 // TODO use real count
});
this.get('model.contributors') this.get('contributors')
.findBy('id', recipientId) .findBy('id', recipientId.toString())
.incrementProperty('balance', amount.toNumber()); .incrementProperty('balance', amount.toNumber());
}, },
_handleProposalVoted(proposalId, voter, totalVotes) { _handleProposalVoted(proposalId, voter, totalVotes) {
this.get('model.proposals') this.get('proposals')
.findBy('id', proposalId.toNumber()) .findBy('id', proposalId.toString())
.setProperties({ 'votesCount': totalVotes }); .setProperties({ 'votesCount': totalVotes });
}, },
_handleTransfer(data) { _handleTransfer(from, to, value) {
this.get('model.contributors') value = value.toNumber();
.findBy('address', data.args.from) this.get('contributors')
.incrementProperty('balance', - data.args.value.toNumber()); .findBy('address', from)
this.get('model.contributors') .decrementProperty('balance', value);
.findBy('address', data.args.to) this.get('contributors')
.incrementProperty('balance', data.args.value.toNumber()); .findBy('address', to)
.incrementProperty('balance', value);
}, },
@@ -125,7 +100,7 @@ export default Ember.Controller.extend({
save(contributor) { save(contributor) {
return this.get('kredits').addContributor(contributor) return this.get('kredits').addContributor(contributor)
.then((contributor) => { .then((contributor) => {
this.get('model.contributors').pushObject(contributor); this.get('contributors').pushObject(contributor);
return contributor; return contributor;
}); });
} }
+6 -6
View File
@@ -1,4 +1,5 @@
import EmberObject from 'ember-object'; import EmberObject from 'ember-object';
import { alias } from 'ember-computed';
export default EmberObject.extend({ export default EmberObject.extend({
// Contract // Contract
@@ -11,6 +12,9 @@ export default EmberObject.extend({
executed: null, executed: null,
ipfsHash: null, ipfsHash: null,
// Shortcuts
isExecuted: alias('executed'),
// IPFS // IPFS
kind: null, kind: null,
description: null, description: null,
@@ -18,10 +22,6 @@ export default EmberObject.extend({
url: null, url: null,
ipfsData: '', ipfsData: '',
// Deprecated // Relationships
recipientAddress: null, contributor: null,
recipientName: null,
recipientProfile: null,
// TODO: add contributor relation
}); });
+20 -20
View File
@@ -109,24 +109,22 @@ export default Service.extend({
}); });
}, },
// TODO: Should be part of the service buildModel(name, attributes) {
buildContributor(attributes) { debug('[kredits] build', name, attributes);
debug('[kredits] buildContributor', attributes); let model = getOwner(this).lookup(`model:${name}`);
let contributor = getOwner(this).lookup('model:contributor'); // coerce id to string
contributor.setProperties(attributes); if (attributes.id) {
return contributor; attributes.id = attributes.id.toString();
}, }
buildProposal(attributes) { model.setProperties(attributes);
debug('[kredits] buildProposal', attributes); return model;
let proposal = getOwner(this).lookup('model:proposal');
proposal.setProperties(attributes);
return proposal;
}, },
getContributorById(id) { getContributorById(id) {
id = ethers.utils.bigNumberify(id);
return this.get('contributorsContract') return this.get('contributorsContract')
.then((contract) => contract.getContributorById(id)) .then((contract) => contract.getContributorById(id))
.then(this.reassembleIpfsHash) .then(this.reassembleIpfsHash)
@@ -135,7 +133,7 @@ export default Service.extend({
let isCurrentUser = this.get('currentUserAccounts').includes(address); let isCurrentUser = this.get('currentUserAccounts').includes(address);
return { return {
id: id.toString(), id: id,
address, address,
balance: balance.toNumber(), balance: balance.toNumber(),
ipfsHash, ipfsHash,
@@ -148,7 +146,7 @@ export default Service.extend({
return this.fetchAndMergeIpfsData(data, ContributorSerializer); return this.fetchAndMergeIpfsData(data, ContributorSerializer);
}) })
.then((attributes) => { .then((attributes) => {
return this.buildContributor(attributes); return this.buildModel('contributor', attributes);
}); });
}, },
@@ -203,6 +201,8 @@ export default Service.extend({
}, },
getProposalById(id) { getProposalById(id) {
id = ethers.utils.bigNumberify(id);
return this.get('kreditsContract') return this.get('kreditsContract')
.then((contract) => contract.proposals(id)) .then((contract) => contract.proposals(id))
.then(this.reassembleIpfsHash) .then(this.reassembleIpfsHash)
@@ -217,9 +217,9 @@ export default Service.extend({
ipfsHash, ipfsHash,
}) => { }) => {
return { return {
id: id.toString(), id: id,
creatorAddress, creatorAddress,
recipientId: recipientId.toNumber(), recipientId: recipientId.toString(),
votesCount: votesCount.toNumber(), votesCount: votesCount.toNumber(),
votesNeeded: votesNeeded.toNumber(), votesNeeded: votesNeeded.toNumber(),
amount: amount.toNumber(), amount: amount.toNumber(),
@@ -232,7 +232,7 @@ export default Service.extend({
return this.fetchAndMergeIpfsData(data, ContributionSerializer); return this.fetchAndMergeIpfsData(data, ContributionSerializer);
}) })
.then((attributes) => { .then((attributes) => {
return this.buildProposal(attributes); return this.buildModel('proposal', attributes);
}); });
}, },
@@ -296,7 +296,7 @@ export default Service.extend({
}) })
.then((data) => { .then((data) => {
debug('[kredits] add contributor response', data); debug('[kredits] add contributor response', data);
return this.buildContributor(attributes); return this.buildModel('contributor', attributes);
}); });
}, },
@@ -333,7 +333,7 @@ export default Service.extend({
}) })
.then((data) => { .then((data) => {
debug('[kredits] add proposal response', data); debug('[kredits] add proposal response', data);
return this.buildProposal(attributes); return this.buildModel('proposal', attributes);
}); });
}, },
+10 -8
View File
@@ -30,11 +30,13 @@
<h2>Open Proposals</h2> <h2>Open Proposals</h2>
</header> </header>
<div class="content"> <div class="content">
{{!-- TODO: We need a better naming for kredits.hasAccounts --}}
{{proposal-list proposals=proposalsOpenSorted {{proposal-list proposals=proposalsOpenSorted
confirmAction="confirmProposal" confirmAction="confirmProposal"
contractInteractionEnabled=contractInteractionEnabled}} contractInteractionEnabled=kredits.hasAccounts}}
{{#if contractInteractionEnabled}} {{!-- TODO: We need a better naming --}}
{{#if kredits.hasAccounts}}
<p class="actions"> <p class="actions">
{{#link-to 'proposals.new'}}Create new proposal{{/link-to}} {{#link-to 'proposals.new'}}Create new proposal{{/link-to}}
</p> </p>
@@ -51,7 +53,8 @@
{{proposal-list proposals=proposalsClosedSorted {{proposal-list proposals=proposalsClosedSorted
confirmAction="confirmProposal"}} confirmAction="confirmProposal"}}
{{#if contractInteractionEnabled}} {{!-- TODO: We need a better naming --}}
{{#if kredits.hasAccounts}}
<p class="actions"> <p class="actions">
{{#link-to 'proposals.new'}}Create new proposal{{/link-to}} {{#link-to 'proposals.new'}}Create new proposal{{/link-to}}
</p> </p>
@@ -65,11 +68,10 @@
</header> </header>
<div class="content"> <div class="content">
{{!-- {{#if currentUser.isCore}}
TODO: {{add-contributor contributors=model.contributors save=(action 'save')}}
only show the form if currentUser.isCore else show: {{else}}
Only core team members can add new contributors. Please ask someone to set you up. Only core team members can add new contributors. Please ask someone to set you up.
--}} {{/if}}
{{add-contributor contributors=model.contributors save=(action 'save')}}
</div> </div>
</section> </section>
@@ -7,7 +7,6 @@ module('Serializers contribution');
test('#serialize returns a valid JSON-LD representation', function(assert) { test('#serialize returns a valid JSON-LD representation', function(assert) {
let serialized = ContributionSerializer.serialize({ let serialized = ContributionSerializer.serialize({
recipientAddress: '0xd4a64570b12da659ee4bbd41c3509b7b1f9c51ac',
kind: 'design', kind: 'design',
description: 'New logo design', description: 'New logo design',
url: 'http://opensourcedesign.org', url: 'http://opensourcedesign.org',