Merge pull request #123 from 67P/feature/122-edit_contributors

Update contributor profiles
This commit was merged in pull request #123.
This commit is contained in:
2019-06-02 01:56:16 +02:00
committed by GitHub
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
});
}
});
+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>