Update contributor profiles #123

Merged
raucao merged 2 commits from feature/122-edit_contributors into master 2019-06-01 23:56:17 +00:00
11 changed files with 163 additions and 68 deletions
+7 -2
View File
@@ -1,6 +1,7 @@
import Component from '@ember/component'; import Component from '@ember/component';
import { and, notEmpty } from '@ember/object/computed'; import { and, notEmpty } from '@ember/object/computed';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { isPresent } from '@ember/utils';
export default Component.extend({ export default Component.extend({
@@ -26,6 +27,12 @@ export default Component.extend({
init () { init () {
this._super(...arguments); this._super(...arguments);
this.setDefaultAttributes();
this.reset();
},
setDefaultAttributes () {
if (isPresent(this.attributes)) { return; }
this.set('attributes', { this.set('attributes', {
account: null, account: null,
@@ -37,8 +44,6 @@ export default Component.extend({
gitea_username: null, gitea_username: null,
wiki_username: null wiki_username: null
}); });
this.reset();
}, },
reset: function() { reset: function() {
+24 -36
View File
@@ -1,62 +1,50 @@
<form {{action "submit" on="submit"}}> <form {{action "submit" on="submit"}}>
<p> <p>
{{input name="account" <label for="c-account">Ethereum account</label>
type="text" {{input name="account" id="c-account"
type="text" value=account
placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4" placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4"
value=account
class=(if isValidAccount "valid" "")}} class=(if isValidAccount "valid" "")}}
</p> </p>
<p> <p>
<select required onchange={{action (mut kind) value="target.value"}}> <label for="c-kind">Kind</label>
<select required onchange={{action (mut kind) value="target.value"}} id="c-kind">
<option value="person" selected={{eq kind "person"}}>Person</option> <option value="person" selected={{eq kind "person"}}>Person</option>
<option value="organization" selected={{eq kind "organization"}}>Organization</option> <option value="organization" selected={{eq kind "organization"}}>Organization</option>
</select> </select>
</p> </p>
<p> <p>
{{input name="name" <label for="c-name">Name</label>
type="text" {{input name="name" type="text" value=name placeholder="Zero Cool"
placeholder="Name" class=(if isValidName "valid" "") id="c-name"}}
value=name
class=(if isValidName "valid" "")}}
</p> </p>
<p> <p>
{{input name="url" <label for="c-url">URL</label>
type="text" {{input name="url" type="text" value=url placeholder="http://zerocool.bit"
placeholder="URL" class=(if isValidURL "valid" "") id="c-url"}}
value=url
class=(if isValidURL "valid" "")}}
</p> </p>
<p> <p>
{{input name="github_uid" <label for="c-github-uid">GitHub UID</label>
type="text" {{input name="github_uid" type="text" value=github_uid placeholder="2342"
placeholder="GitHub UID (123)" class=(if isValidGithubUID "valid" "") id="c-github-uid"}}
value=github_uid
class=(if isValidGithubUID "valid" "")}}
</p> </p>
<p> <p>
{{input name="github_username" <label for="c-github-username">GitHub username</label>
type="text" {{input name="github_username" type="text" value=github_username placeholder="zerocool"
placeholder="GitHub username" class=(if isValidGithubUsername "valid" "") id="c-github-username"}}
value=github_username
class=(if isValidGithubUsername "valid" "")}}
</p> </p>
<p> <p>
{{input name="gitea_username" <label for="c-gitea-username">Gitea username</label>
type="text" {{input name="gitea_username" type="text" value=gitea_username placeholder="zerocool"
placeholder="Gitea username" class=(if isValidGiteaUsername "valid" "") id="c-gitea-username"}}
value=gitea_username
class=(if isValidGiteaUsername "valid" "")}}
</p> </p>
<p> <p>
{{input name="wiki_username" <label for="c-wiki-username">Wiki username</label>
type="text" {{input name="wiki_username" type="text" value=wiki_username placeholder="ZeroCool"
placeholder="Wiki Username" class=(if isValidWikiUsername "valid" "") id="c-wiki-username"}}
value=wiki_username
class=(if isValidWikiUsername "valid" "")}}
</p> </p>
<p class="actions"> <p class="actions">
{{input type="submit" {{input type="submit" disabled=inProgress
disabled=inProgress
value=(if inProgress "Processing" "Save")}} value=(if inProgress "Processing" "Save")}}
</p> </p>
</form> </form>
@@ -26,6 +26,9 @@
<a href="https://ipfs.io/ipfs/{{c.contributor.ipfsHash}}" target="_blank" rel="noopener">Inspect IPFS profile</a> <a href="https://ipfs.io/ipfs/{{c.contributor.ipfsHash}}" target="_blank" rel="noopener">Inspect IPFS profile</a>
</li> </li>
{{/if}} {{/if}}
<li>
{{link-to "Edit profile" "contributors.edit" c.contributor.id}}
</li>
</ul> </ul>
{{#if c.showMetadata}} {{#if c.showMetadata}}
<pre>{{c.contributor.ipfsData}}</pre> <pre>{{c.contributor.ipfsData}}</pre>
+18
View File
@@ -0,0 +1,18 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
actions: {
save (attributes) {
return this.kredits
.updateContributor(this.model.id, attributes)
.then(() => this.transitionToRoute('index'))
}
}
});
+3 -8
View File
@@ -1,21 +1,16 @@
import Controller from '@ember/controller'; import Controller from '@ember/controller';
import { alias } from '@ember/object/computed';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
export default Controller.extend({ export default Controller.extend({
kredits: service(), kredits: service(),
contributors: alias('kredits.contributors'),
actions: { actions: {
save (contributor) { save (contributor) {
return this.kredits.addContributor(contributor) return this.kredits
.then(contributor => { .addContributor(contributor)
this.transitionToRoute('index'); .then(() => this.transitionToRoute('index'))
return contributor;
});
} }
} }
+1
View File
@@ -15,6 +15,7 @@ Router.map(function() {
}); });
this.route('contributors', function() { this.route('contributors', function() {
this.route('new'); this.route('new');
this.route('edit', { path: ':id/edit' });
}); });
}); });
+29
View File
@@ -0,0 +1,29 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import { alias } from '@ember/object/computed';
export default Route.extend({
kredits: service(),
contributors: alias('kredits.contributors'),
model(params) {
return this.kredits.contributors.findBy('id', params.id);
},
setupController (controller, model) {
this._super(controller, model);
controller.set('attributes', {
account: model.account,
name: model.name,
kind: model.kind,
url: model.url,
github_username: model.github_username,
github_uid: model.github_uid,
gitea_username: model.gitea_username,
wiki_username: model.wiki_username
bumi commented 2019-06-01 10:16:57 +00:00 (Migrated from github.com)
Review

do you think we can use the accounts array here already? with adding more services we at some point would want to directly add entries to the accounts array.

do you think we can use the `accounts` array here already? with adding more services we at some point would want to directly add entries to the accounts array.
raucao commented 2019-06-01 11:01:01 +00:00 (Migrated from github.com)
Review

That should be a separate PR, as it requires quite some changes in the code.

That should be a separate PR, as it requires quite some changes in the code.
});
}
});
+53 -21
View File
@@ -47,7 +47,7 @@ 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.toString());
@@ -87,7 +87,7 @@ export default Service.extend({
// This is called in the application route's beforeModel(). So it is // This is called in the application route's beforeModel(). So it is
// initialized before everything else, and we can rely on the ethProvider and // initialized before everything else, and we can rely on the ethProvider and
// the potential currentUserAccounts to be available // the potential currentUserAccounts to be available
getEthProvider: function() { getEthProvider () {
let ethProvider; let ethProvider;
return new RSVP.Promise(async (resolve) => { return new RSVP.Promise(async (resolve) => {
@@ -136,7 +136,7 @@ export default Service.extend({
}); });
}, },
setup() { setup () {
return this.getEthProvider().then((providerAndSigner) => { return this.getEthProvider().then((providerAndSigner) => {
let kredits = new Kredits(providerAndSigner.ethProvider, providerAndSigner.ethSigner, { let kredits = new Kredits(providerAndSigner.ethProvider, providerAndSigner.ethSigner, {
addresses: { Kernel: config.kreditsKernelAddress }, addresses: { Kernel: config.kreditsKernelAddress },
@@ -172,14 +172,14 @@ export default Service.extend({
}), }),
loadInitialData() { loadInitialData () {
return this.getContributors() return this.getContributors()
.then(contributors => this.contributors.pushObjects(contributors)) .then(contributors => this.contributors.pushObjects(contributors))
.then(() => this.getContributions()) .then(() => this.getContributions())
.then(contributions => this.contributions.pushObjects(contributions)) .then(contributions => this.contributions.pushObjects(contributions))
}, },
addContributor(attributes) { addContributor (attributes) {
if (attributes.github_uid) { if (attributes.github_uid) {
const uidInt = parseInt(attributes.github_uid); const uidInt = parseInt(attributes.github_uid);
attributes.github_uid = uidInt; attributes.github_uid = uidInt;
@@ -190,13 +190,24 @@ export default Service.extend({
return this.kredits.Contributor.add(attributes, { gasLimit: 350000 }) return this.kredits.Contributor.add(attributes, { gasLimit: 350000 })
.then(data => { .then(data => {
console.debug('[kredits] add contributor response', data); console.debug('[kredits] add contributor response', data);
const contributor = Contributor.create(attributes);
this.contributors.pushObject(contributor);
return contributor;
}); });
}, },
getContributors() { updateContributor (id, attributes) {
if (attributes.github_uid) {
const uidInt = parseInt(attributes.github_uid);
attributes.github_uid = uidInt;
}
console.debug('[kredits] update contributor', attributes);
return this.kredits.Contributor.updateProfile(id, attributes, { gasLimit: 350000 })
.then(data => {
console.debug('[kredits] updateProfile response', data);
});
},
getContributors () {
return this.kredits.Contributor.all() return this.kredits.Contributor.all()
.then((contributors) => { .then((contributors) => {
return contributors.map((contributor) => { return contributors.map((contributor) => {
@@ -205,7 +216,7 @@ export default Service.extend({
}); });
}, },
addContribution(attributes) { addContribution (attributes) {
console.debug('[kredits] add contribution', attributes); console.debug('[kredits] add contribution', attributes);
return this.kredits.Contribution.addContribution(attributes, { gasLimit: 300000 }) return this.kredits.Contribution.addContribution(attributes, { gasLimit: 300000 })
@@ -220,7 +231,7 @@ export default Service.extend({
}); });
}, },
addProposal(attributes) { addProposal (attributes) {
console.debug('[kredits] add proposal', attributes); console.debug('[kredits] add proposal', attributes);
return this.kredits.Proposal.addProposal(attributes) return this.kredits.Proposal.addProposal(attributes)
@@ -231,7 +242,7 @@ export default Service.extend({
}); });
}, },
getProposals() { getProposals () {
return this.kredits.Proposal.all() return this.kredits.Proposal.all()
.then((proposals) => { .then((proposals) => {
return proposals.map((proposal) => { return proposals.map((proposal) => {
@@ -241,7 +252,7 @@ export default Service.extend({
}); });
}, },
getContributions() { getContributions () {
return this.kredits.Contribution.all({page: {size: 200}}) return this.kredits.Contribution.all({page: {size: 200}})
.then(contributions => { .then(contributions => {
return contributions.map(contribution => { return contributions.map(contribution => {
@@ -251,7 +262,7 @@ export default Service.extend({
}); });
}, },
vote(proposalId) { vote (proposalId) {
console.debug('[kredits] vote for', proposalId); console.debug('[kredits] vote for', proposalId);
return this.kredits.Proposal.functions.vote(proposalId) return this.kredits.Proposal.functions.vote(proposalId)
@@ -261,7 +272,7 @@ export default Service.extend({
}); });
}, },
veto(contributionId) { veto (contributionId) {
console.debug('[kredits] veto against', contributionId); console.debug('[kredits] veto against', contributionId);
return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 }) return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
@@ -292,7 +303,12 @@ export default Service.extend({
}, },
// Contract events // Contract events
addContractEventHandlers() { addContractEventHandlers () {
this.kredits.Contributor
.on('ContributorProfileUpdated', this.handleContributorChange.bind(this))
.on('ContributorAccountUpdated', this.handleContributorChange.bind(this))
.on('ContributorAdded', this.handleContributorChange.bind(this))
this.kredits.Contribution this.kredits.Contribution
.on('ContributionVetoed', this.handleContributionVetoed.bind(this)) .on('ContributionVetoed', this.handleContributionVetoed.bind(this))
@@ -305,7 +321,23 @@ export default Service.extend({
.on('Transfer', this.handleTransfer.bind(this)); .on('Transfer', this.handleTransfer.bind(this));
}, },
handleContributionVetoed(contributionId) { async handleContributorChange (contributorId, ...args) {
console.debug('[kredits] Contributor add/update event received for ID', contributorId);
console.debug('[kredits] Event data:', args);
const contributorData = await this.kredits.Contributor.getById(contributorId);
const newContributor = Contributor.create(contributorData);
const oldContributor = this.contributors.findBy('id', contributorId.toString());
if (oldContributor) {
console.debug('[kredits] old contributor', oldContributor);
this.contributors.removeObject(oldContributor);
}
console.debug('[kredits] new contributor', newContributor);
this.contributors.pushObject(newContributor);
},
handleContributionVetoed (contributionId) {
console.debug('[kredits] ContributionVetoed event received for ', contributionId); console.debug('[kredits] ContributionVetoed event received for ', contributionId);
const contribution = this.contributions.findBy('id', contributionId); const contribution = this.contributions.findBy('id', contributionId);
console.debug('[kredits] contribution', contribution); console.debug('[kredits] contribution', contribution);
@@ -315,7 +347,7 @@ export default Service.extend({
} }
}, },
handleProposalCreated(proposalId) { handleProposalCreated (proposalId) {
let proposal = this.findProposalById(proposalId); let proposal = this.findProposalById(proposalId);
if (proposal) { if (proposal) {
@@ -331,7 +363,7 @@ export default Service.extend({
}, },
// TODO: We may want to reload that proposal to show the voter as voted // TODO: We may want to reload that proposal to show the voter as voted
handleProposalVoted(proposalId, voterId, totalVotes) { handleProposalVoted (proposalId, voterId, totalVotes) {
let proposal = this.findProposalById(proposalId); let proposal = this.findProposalById(proposalId);
if (proposal) { if (proposal) {
@@ -339,7 +371,7 @@ export default Service.extend({
} }
}, },
handleProposalExecuted(proposalId, contributorId, amount) { handleProposalExecuted (proposalId, contributorId, amount) {
let proposal = this.findProposalById(proposalId); let proposal = this.findProposalById(proposalId);
if (proposal.get('isExecuted')) { if (proposal.get('isExecuted')) {
@@ -354,7 +386,7 @@ export default Service.extend({
.incrementProperty('balance', amount); .incrementProperty('balance', amount);
}, },
handleTransfer(from, to, value) { handleTransfer (from, to, value) {
value = value.toNumber(); value = value.toNumber();
this.contributors this.contributors
+11
View File
@@ -17,6 +17,12 @@ section#add-proposal {
} }
} }
label {
display: block;
margin-bottom: 0.5rem;
opacity: 0.7;
}
input[type=text], select { input[type=text], select {
width: 100%; width: 100%;
padding: 1rem; padding: 1rem;
@@ -25,9 +31,14 @@ section#add-proposal {
background-color: rgba(22, 21, 40, 0.3); background-color: rgba(22, 21, 40, 0.3);
color: #fff; color: #fff;
font-size: 1.2rem; font-size: 1.2rem;
transition: border-color 0.1s linear;
&:focus, &.valid { &:focus, &.valid {
background-color: rgba(22, 21, 40, 0.6); background-color: rgba(22, 21, 40, 0.6);
} }
&:focus {
border-color: $blue;
}
&::placeholder { &::placeholder {
color: rgba(238, 238, 238, 0.5); color: rgba(238, 238, 238, 0.5);
} }
+13
View File
@@ -0,0 +1,13 @@
<main class="center-column">
<section id="add-contributor">
<header>
<h2>Update contributor profile</h2>
</header>
<div class="content">
{{add-contributor attributes=attributes save=(action "save")}}
</div>
</section>
</main>
+1 -1
View File
@@ -6,7 +6,7 @@
</header> </header>
<div class="content"> <div class="content">
{{add-contributor contributors=contributors save=(action "save")}} {{add-contributor save=(action "save")}}
</div> </div>
</section> </section>