-
Notifications
You must be signed in to change notification settings - Fork 1.7k
get certifications from BadgeReg, show them in accounts overview #3768
Changes from 13 commits
2b34d76
b32b636
409c4ad
e1c5796
5862f2a
a84cd91
e536290
3dc943e
fd88421
6d20592
bc33231
d67a938
240bab2
afba259
f59f7c5
4c42ded
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,40 +18,61 @@ import { bytesToHex, hex2Ascii } from '~/api/util/format'; | |
|
||
import ABI from './abi/certifier.json'; | ||
|
||
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000'; | ||
const ZERO20 = '0x0000000000000000000000000000000000000000'; | ||
const ZERO32 = '0x0000000000000000000000000000000000000000000000000000000000000000'; | ||
|
||
export default class BadgeReg { | ||
constructor (api, registry) { | ||
this._api = api; | ||
this._registry = registry; | ||
|
||
registry.getContract('badgereg'); | ||
this.certifiers = {}; // by name | ||
this.certifiers = []; // by id | ||
this.contracts = {}; // by name | ||
} | ||
|
||
fetchCertifier (name) { | ||
if (this.certifiers[name]) { | ||
return Promise.resolve(this.certifiers[name]); | ||
nrOfCertifiers () { | ||
return this._registry.getContract('badgereg') | ||
.then((badgeReg) => { | ||
return badgeReg.instance.badgeCount.call({}, []) | ||
.then((count) => count.valueOf()); | ||
}); | ||
} | ||
|
||
fetchCertifier (id) { | ||
if (this.certifiers[id]) { | ||
return Promise.resolve(this.certifiers[id]); | ||
} | ||
return this._registry.getContract('badgereg') | ||
.then((badgeReg) => { | ||
return badgeReg.instance.fromName.call({}, [name]) | ||
.then(([ id, address ]) => { | ||
return Promise.all([ | ||
badgeReg.instance.meta.call({}, [id, 'TITLE']), | ||
badgeReg.instance.meta.call({}, [id, 'IMG']) | ||
]) | ||
.then(([ title, img ]) => { | ||
title = bytesToHex(title); | ||
title = title === ZERO ? null : hex2Ascii(title); | ||
if (bytesToHex(img) === ZERO) img = null; | ||
return badgeReg.instance.badge.call({}, [ id ]); | ||
}) | ||
.then(([ address, name ]) => { | ||
if (address === ZERO20) throw new Error(`Certifier ${id} does not exist.`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Considder putting this across 2 lines with a blank space between the blocks -
|
||
name = bytesToHex(name); | ||
name = name === ZERO32 ? null : hex2Ascii(name); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same split comment as above, would make life easier going forward, hence -
|
||
return this.fetchMeta(id) | ||
.then(({ title, icon }) => { | ||
const data = { address, id, name, title, icon }; | ||
this.certifiers[id] = data; | ||
return data; | ||
}); | ||
}); | ||
} | ||
|
||
const data = { address, name, title, icon: img }; | ||
this.certifiers[name] = data; | ||
return data; | ||
}); | ||
}); | ||
fetchMeta (id) { | ||
return this._registry.getContract('badgereg') | ||
.then((badgeReg) => { | ||
return Promise.all([ | ||
badgeReg.instance.meta.call({}, [id, 'TITLE']), | ||
badgeReg.instance.meta.call({}, [id, 'IMG']) | ||
]); | ||
}) | ||
.then(([ title, icon ]) => { | ||
title = bytesToHex(title); | ||
title = title === ZERO32 ? null : hex2Ascii(title); | ||
if (bytesToHex(icon) === ZERO32) icon = null; | ||
return { title, icon }; | ||
}); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,38 +14,78 @@ | |
// You should have received a copy of the GNU General Public License | ||
// along with Parity. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
import Contracts from '~/contracts'; | ||
import { addCertification } from './actions'; | ||
import { uniq } from 'lodash'; | ||
|
||
const knownCertifiers = [ 'smsverification' ]; | ||
import ABI from '~/contracts/abi/certifier.json'; | ||
import Contract from '~/api/contract'; | ||
import Contracts from '~/contracts'; | ||
import { addCertification, removeCertification } from './actions'; | ||
|
||
export default class CertificationsMiddleware { | ||
toMiddleware () { | ||
const api = Contracts.get()._api; | ||
const badgeReg = Contracts.get().badgeReg; | ||
const contract = new Contract(api, ABI); | ||
const Confirmed = contract.events.find((e) => e.name === 'Confirmed'); | ||
const Revoked = contract.events.find((e) => e.name === 'Revoked'); | ||
|
||
let certifiers = []; | ||
let accounts = []; // these are addresses | ||
|
||
const fetchConfirmedEvents = (dispatch) => { | ||
if (certifiers.length === 0 || accounts.length === 0) return; | ||
api.eth.getLogs({ | ||
fromBlock: 0, | ||
toBlock: 'latest', | ||
address: certifiers.map((c) => c.address), | ||
topics: [ [ Confirmed.signature, Revoked.signature ], accounts ] | ||
}) | ||
.then((logs) => contract.parseEventLogs(logs)) | ||
.then((logs) => { | ||
logs.forEach((log) => { | ||
const certifier = certifiers.find((c) => c.address === log.address); | ||
if (!certifier) throw new Error(`Could not find certifier at ${log.address}.`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same single-line comment as above for the same reasons. |
||
const { id, name, title, icon } = certifier; | ||
if (log.event === 'Revoked') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Really picky, but would prefer a line before this block, just indicates a break between assigning and doing. (Not a crisis, just aids readability once again) |
||
dispatch(removeCertification(log.params.who.value, id)); | ||
} else { | ||
dispatch(addCertification(log.params.who.value, id, name, title, icon)); | ||
} | ||
}); | ||
}) | ||
.catch((err) => { | ||
console.error('Failed to fetch Confirmed events:', err); | ||
}); | ||
}; | ||
|
||
return (store) => (next) => (action) => { | ||
if (action.type !== 'fetchCertifications') { | ||
return next(action); | ||
} | ||
|
||
const { address } = action; | ||
const badgeReg = Contracts.get().badgeReg; | ||
|
||
knownCertifiers.forEach((name) => { | ||
badgeReg.fetchCertifier(name) | ||
.then((cert) => { | ||
return badgeReg.checkIfCertified(cert.address, address) | ||
.then((isCertified) => { | ||
if (isCertified) { | ||
const { name, title, icon } = cert; | ||
store.dispatch(addCertification(address, name, title, icon)); | ||
if (action.type === 'fetchCertifiers') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider using a switch statement for |
||
badgeReg.nrOfCertifiers().then((count) => { | ||
new Array(+count).fill(null).forEach((_, id) => { | ||
badgeReg.fetchCertifier(id) | ||
.then((cert) => { | ||
if (!certifiers.some((c) => c.id === cert.id)) { | ||
certifiers = certifiers.concat(cert); | ||
fetchConfirmedEvents(store.dispatch); | ||
} | ||
}) | ||
.catch((err) => { | ||
console.warn(`Could not fetch certifier ${id}:`, err); | ||
}); | ||
}) | ||
.catch((err) => { | ||
if (err) { | ||
console.error(`Failed to check if ${address} certified by ${name}:`, err); | ||
} | ||
}); | ||
}); | ||
}); | ||
} else if (action.type === 'fetchCertifications') { | ||
const { address } = action; | ||
|
||
if (!accounts.includes(address)) { | ||
accounts = accounts.concat(address); | ||
fetchConfirmedEvents(store.dispatch); | ||
} | ||
} else if (action.type === 'setVisibleAccounts') { | ||
const { addresses } = action; | ||
accounts = uniq(accounts.concat(addresses)); | ||
fetchConfirmedEvents(store.dispatch); | ||
} else return next(action); | ||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,17 +17,25 @@ | |
const initialState = {}; | ||
|
||
export default (state = initialState, action) => { | ||
if (action.type !== 'addCertification') { | ||
return state; | ||
if (action.type === 'addCertification') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. switch statement would be good here as well, since we are only checking the type, default is the state return. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing it to a switch statement in this case means that the variable declarations aren't as local anymore. The linter will complain. Moving them up is ugly because we're assigning stuff we may not need. |
||
const { address, id, name, icon, title } = action; | ||
const certifications = state[address] || []; | ||
|
||
if (certifications.some((c) => c.id === id)) { | ||
return state; | ||
} | ||
const newCertifications = certifications.concat({ id, name, icon, title }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. linebreak before would be good, the rest of the callback is actually nice and readable. |
||
|
||
return { ...state, [address]: newCertifications }; | ||
} | ||
|
||
const { address, name, icon, title } = action; | ||
const certifications = state[address] || []; | ||
if (action.type === 'removeCertification') { | ||
const { address, id } = action; | ||
const certifications = state[address] || []; | ||
|
||
if (certifications.some((c) => c.name === name)) { | ||
return state; | ||
const newCertifications = certifications.filter((c) => c.id !== id); | ||
return { ...state, [address]: newCertifications }; | ||
} | ||
const newCertifications = certifications.concat({ name, icon, title }); | ||
|
||
return { ...state, [address]: newCertifications }; | ||
return state; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,10 +16,8 @@ | |
|
||
import React, { Component, PropTypes } from 'react'; | ||
import { connect } from 'react-redux'; | ||
import { bindActionCreators } from 'redux'; | ||
|
||
import { hashToImageUrl } from '~/redux/providers/imagesReducer'; | ||
import { fetchCertifications } from '~/redux/providers/certifications/actions'; | ||
|
||
import defaultIcon from '../../../assets/images/certifications/unknown.svg'; | ||
|
||
|
@@ -29,14 +27,7 @@ class Certifications extends Component { | |
static propTypes = { | ||
account: PropTypes.string.isRequired, | ||
certifications: PropTypes.array.isRequired, | ||
dappsUrl: PropTypes.string.isRequired, | ||
|
||
fetchCertifications: PropTypes.func.isRequired | ||
} | ||
|
||
componentWillMount () { | ||
const { account, fetchCertifications } = this.props; | ||
fetchCertifications(account); | ||
dappsUrl: PropTypes.string.isRequired | ||
} | ||
|
||
render () { | ||
|
@@ -73,15 +64,12 @@ function mapStateToProps (_, initProps) { | |
|
||
return (state) => { | ||
const certifications = state.certifications[account] || []; | ||
return { certifications }; | ||
const dappsUrl = state.api.dappsUrl; | ||
return { certifications, dappsUrl }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Less squashing, break would be good before the return line. |
||
}; | ||
} | ||
|
||
function mapDispatchToProps (dispatch) { | ||
return bindActionCreators({ fetchCertifications }, dispatch); | ||
} | ||
|
||
export default connect( | ||
mapStateToProps, | ||
mapDispatchToProps | ||
null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could remove completely There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually like |
||
)(Certifications); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nr
->number
(or just
certifierCount
)