Skip to content

Commit

Permalink
Merge from dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Quazia committed Nov 12, 2018
2 parents f910812 + 75483aa commit 90d4421
Show file tree
Hide file tree
Showing 15 changed files with 410 additions and 333 deletions.
5 changes: 2 additions & 3 deletions README.md
@@ -1,6 +1,6 @@
# That Planning Suite

[![Build Status](https://travis-ci.org/Giveth/planning-app.svg?branch=dev)](https://travis-ci.org/Giveth/planning-app) [![Coverage Status](https://coveralls.io/repos/github/Giveth/planning-app/badge.svg?branch=dev)](https://coveralls.io/github/Giveth/planning-app?branch=dev)
[![Build Status](https://img.shields.io/travis/spacedecentral/planning-suite.svg?style=flat-square)](https://travis-ci.org/spacedecentral/planning-suite) [![Coverage Status](https://img.shields.io/coveralls/github/spacedecentral/planning-suite.svg?style=flat-square)](https://coveralls.io/github/spacedecentral/planning-suite)

<p align="center">
<a href="#development-setup">Development Setup</a> •
Expand Down Expand Up @@ -53,7 +53,7 @@ The Planning Suite is a collection of six Aragon Apps that supports the followin
- **Dynamic Payout:** Payroll contract that allows for dynamic allocations that are determined using range voting.
- **Payout Engine:** Pay sharing contract using a percentage-based distribution system, where the percentages are determined using range voting.
- **Address Book:** Maintain a list of Ethereum addresses (external contacts/collaborators) mapped to human-readable names.
- **Fixed Payout:** The address book will enable a more user-friendly way to access common addresses a DAO uses, making it easier to setup Fixed Payouts in various Aragon apps.
- **Fixed Payout:** The address book will enable a more user-friendly way to access common addresses a DAO uses, making it easier to setup Fixed Payouts in various Aragon apps.
- **Range Voting:** Vote on the percentage of an allocation that distinct tasks, projects, or people should receive. Unique forwarding pattern allows for data to be added to EVM scripts within Aragon.
- **Projects:** Allow Github issues to be collectively prioritized in addition to applying bulk bounties.
- **Github Integration:** Before we can utilize the decentralized git tool, it would be ideal to have an integration with a Github-based bounty system to provide immediate utility to Aragon DAOs.
Expand All @@ -64,7 +64,6 @@ The Planning Suite is a collection of six Aragon Apps that supports the followin
- **Consensus:** Allow for special voting sessions to be created, where the aim is to reach consensus among the voting session participants.
- **Rewards:** Distributes payments to token holders based on the number of tokens one has earned in a specific cycle of time (one-time reward) or based on the total tokens one holds (dividend).


#### Please review the [White Paper](http://goo.gl/eXAybm) for full details.

## Design Concepts
Expand Down
4 changes: 3 additions & 1 deletion apps/allocations/contracts/Allocations.sol
Expand Up @@ -104,7 +104,9 @@ contract Allocations is AragonApp, Fundable { // solium-disable-line blank-lines
}


function getPayout(uint256 _payoutId) public view returns(uint256 balance, uint256 limit, string metadata, address token, address proxy, uint256 amount) {
function getPayout(uint256 _payoutId) public view
returns(uint256 balance, uint256 limit, string metadata, address token, address proxy, uint256 amount)
{
Payout storage payout = payouts[_payoutId];
limit = payout.limit;
balance = payout.balance;
Expand Down
16 changes: 4 additions & 12 deletions apps/allocations/test/allocations.test.js
Expand Up @@ -52,13 +52,16 @@ contract('Allocations App', accounts => {
{ from: root }
)

// TODO: Revert to only use 2 params when truffle is updated
// TODO: Revert to use regular function call when truffle gets updated
// read: https://github.com/Giveth/planning-app/pull/243
let receipt = await dao.newAppInstance(
'0x1234',
(await Allocations.new()).address,
0x0,
false,
{ from: root }
)

app = Allocations.at(
receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
)
Expand Down Expand Up @@ -90,17 +93,6 @@ contract('Allocations App', accounts => {
// receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
// )

// TODO: Revert to only use 2 params when truffle is updated
// read: https://github.com/Giveth/planning-app/pull/243
receipt = await dao.newAppInstance(
'0x2345',
(await Allocations.new()).address,
{ from: root }
)

allocation = Allocations.at(
receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
)
await app.initialize({ from: accounts[0] })
})

Expand Down
1 change: 0 additions & 1 deletion apps/projects/app/components/App/App.js
Expand Up @@ -74,7 +74,6 @@ class App extends React.Component {
render() {
const { panel } = this.state
const PanelContent = panel.content
console.log('current project props:', this.props.repos)

return (
<StyledAragonApp publicUrl={ASSETS_URL}>
Expand Down
190 changes: 147 additions & 43 deletions apps/projects/app/script.js
@@ -1,24 +1,64 @@
import Aragon, { providers } from '@aragon/client'
import 'rxjs/add/operator/first' // Make sure observables have .first
export { combineLatest } from 'rxjs/observable/combineLatest'
import { first, of } from 'rxjs' // Make sure observables have .first
import { combineLatest } from 'rxjs'
import { empty } from 'rxjs/observable/empty'

const app = new Aragon()
import { GraphQLClient } from 'graphql-request'

// Hook up the script as an aragon.js store
app.store(async (state, { event, returnValues }) => {
let nextState = {
...state,
// Fetch the app's settings, if we haven't already
//...(!hasLoadedVoteSettings(state) ? await loadVoteSettings() : {}),
}
const authToken = ''
const client = new GraphQLClient('https://api.github.com/graphql', {
headers: {
Authorization: 'Bearer ' + authToken,
},
})

switch (event) {
case 'NewPayout':
nextState = await newPayout(nextState, returnValues)
break
const toAscii = hex => {
// Find termination
let str = ''
let i = 0,
l = hex.length
if (hex.substring(0, 2) === '0x') {
i = 2
}
for (; i < l; i += 2) {
let code = parseInt(hex.substr(i, 2), 16)
str += String.fromCharCode(code)
}

return str
}

return nextState
const repoData = id => `{
node(id: "${id}") {
... on Repository {
name
description
defaultBranchRef {
target {
...on Commit {
history {
totalCount
}
}
}
}
collaborators {
totalCount
}
}
}
}`

const getRepoData = repo => client.request(repoData(repo))

const app = new Aragon()
let appState
app.events().subscribe(handleEvents)

app.state().subscribe(state => {
console.log('Projects: entered state subscription:\n', state)
appState = state ? state : { repos: [] }
//appState = state
})

/***********************
Expand All @@ -27,12 +67,41 @@ app.store(async (state, { event, returnValues }) => {
* *
***********************/

async function newPayout(state, { payoutId }) {
const transform = ({ data, ...payout }) => ({
...payout,
data: { ...data, executed: true },
async function handleEvents(response) {
let nextState
switch (response.event) {
case 'RepoAdded':
nextState = await syncRepos(appState, response.returnValues)
console.log('RepoAdded Received', response.returnValues, nextState)
break
case 'RepoRemoved':
nextState = await syncRepos(appState, response.returnValues)
console.log('RepoRemoved Received', response.returnValues, nextState)

break
case 'BountyAdded':
nextState = await syncRepos(appState, response.returnValues)
console.log('BountyAdded Received', response.returnValues, nextState)

break
default:
console.log('Unknown event catched:', response)
}
app.cache('state', nextState)
}

async function syncRepos(state, { id, ...eventArgs }) {
console.log('syncRepos: arguments from events:', ...eventArgs)

const transform = ({ ...repo }) => ({
...repo,
})
return updateState(state, payoutId, transform)
try {
let updatedState = await updateState(state, id, transform)
return updatedState
} catch (err) {
console.error('updateState failed to return:', err)
}
}

/***********************
Expand All @@ -41,41 +110,76 @@ async function newPayout(state, { payoutId }) {
* *
***********************/

function loadPayoutData(payoutId) {
function loadRepoData(id) {
console.log('loadRepoData entered')
return new Promise(resolve => {
combineLatest(app.call('getPayout', payoutId)).subscribe(
([payout, metadata]) => {}
)
combineLatest(app.call('getRepo', id)).subscribe(([{ _owner, _repo }]) => {
console.log('loadRepoData:', _owner, _repo)
let [owner, repo] = [toAscii(_owner), toAscii(_repo)]
getRepoData(repo).then(
({
node: {
name,
description,
collaborators: { totalCount: collaborators },
defaultBranchRef: {
target: {
history: { totalCount: commits },
},
},
},
}) => {
let metadata = {
name,
description,
collaborators,
commits,
}
resolve({ owner, repo, metadata })
}
)
})
})
}

async function updatePayouts(payouts, payoutId, transform) {
const payoutIndex = payouts.findIndex(payout => payout.payoutId === payoutId)
async function checkReposLoaded(repos, id, transform) {
const repoIndex = repos.findIndex(repo => repo.id === id)
console.log('checkReposLoaded, repoIndex:', repos, id)
const { metadata, ...data } = await loadRepoData(id)

if (payoutIndex === -1) {
if (repoIndex === -1) {
// If we can't find it, load its data, perform the transformation, and concat
return payouts.concat(
console.log('repo not found: retrieving from chain')
return repos.concat(
await transform({
payoutId,
data: await loadPayoutData(payoutId),
id,
data: { ...data },
metadata,
})
)
} else {
const nextPayouts = Array.from(payouts)
nextPayouts[payoutIndex] = await transform(nextPayouts[payoutIndex])
return nextPayouts
const nextRepos = Array.from(repos)
nextRepos[repoIndex] = await transform({
id,
data: { ...data },
metadata,
})
return nextRepos
}
}

async function updateState(state, payoutId, transform) {
const { payouts = [] } = state

return {
...state,
payouts: await updatePayouts(payouts, payoutId, transform),
async function updateState(state, id, transform) {
const { repos = [] } = state
try {
let newRepos = await checkReposLoaded(repos, id, transform)
let newState = { ...state, repos: newRepos }
return newState
} catch (err) {
console.error(
'Update repos failed to return:',
err,
'here\'s what returned in NewRepos',
newRepos
)
}
}

// Apply transmations to a vote received from web3
// Note: ignores the 'open' field as we calculate that locally
//
4 changes: 4 additions & 0 deletions apps/projects/test/projects.test.js
Expand Up @@ -51,9 +51,13 @@ contract('Projects App', accounts => {
)

//Deploy Contract to be tested
// TODO: Revert to use regular function call when truffle gets updated
// read: https://github.com/Giveth/planning-app/pull/243
let receipt = await dao.newAppInstance(
'0x1234',
(await Projects.new()).address,
0x0,
false,
{ from: root }
)
app = Projects.at(
Expand Down

0 comments on commit 90d4421

Please sign in to comment.