Browse Source

init2

develop
Ezerous 6 years ago
parent
commit
068850e0ee
  1. 1
      app/package.json
  2. 7
      app/src/containers/LoadingContainer.js
  3. 40
      app/src/containers/PostList.js
  4. 48
      app/src/containers/ProfileInformation.js
  5. 15
      app/src/containers/TopicContainer.js
  6. 37
      app/src/containers/TopicList.js
  7. 25
      app/src/containers/UsernameFormContainer.js
  8. 20
      app/src/redux/sagas/orbitSaga.js
  9. 3
      app/src/redux/sagas/transactionsSaga.js
  10. 20
      app/src/utils/levelUtils.js
  11. 91
      app/src/utils/orbitUtils.js
  12. 92
      contracts/Forum.sol

1
app/package.json

@ -11,7 +11,6 @@
"drizzle": "1.4.0", "drizzle": "1.4.0",
"history": "4.9.0", "history": "4.9.0",
"ipfs": "0.35.0", "ipfs": "0.35.0",
"level": "5.0.1",
"lodash.isequal": "4.5.0", "lodash.isequal": "4.5.0",
"orbit-db": "0.21.0-rc.1", "orbit-db": "0.21.0-rc.1",
"orbit-db-keystore": "0.2.1", "orbit-db-keystore": "0.2.1",

7
app/src/containers/LoadingContainer.js

@ -17,9 +17,8 @@ class LoadingContainer extends Component {
<p><strong>This browser has no connection to the Ethereum network.</strong></p> <p><strong>This browser has no connection to the Ethereum network.</strong></p>
Please make sure that: Please make sure that:
<ul> <ul>
<li>You use MetaMask or a dedicated Ethereum browser</li> <li>MetaMask is unlocked and pointed to the correct network</li>
<li>They are pointed to the correct network</li> <li>The app has been granted the right to connect to your account</li>
<li>Your account is unlocked and the app has the rights to access it</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -34,6 +33,7 @@ class LoadingContainer extends Component {
<div> <div>
<img src={ethereum_logo} alt="ethereum_logo" className="loading-img"/> <img src={ethereum_logo} alt="ethereum_logo" className="loading-img"/>
<p><strong>We can't find any Ethereum accounts!</strong></p> <p><strong>We can't find any Ethereum accounts!</strong></p>
<p>Please make sure that MetaMask is unlocked.</p>
</div> </div>
</div> </div>
</main> </main>
@ -76,6 +76,7 @@ class LoadingContainer extends Component {
<div> <div>
<img src={orbitdb_logo} alt="orbitdb_logo" className="loading-img"/> <img src={orbitdb_logo} alt="orbitdb_logo" className="loading-img"/>
<p><strong>Preparing OrbitDB...</strong></p> <p><strong>Preparing OrbitDB...</strong></p>
<p>Please sign the transaction in MetaMask to create the databases.</p>
</div> </div>
</div> </div>
</main> </main>

40
app/src/containers/PostList.js

@ -5,6 +5,7 @@ import { drizzle } from '../index';
import Post from './Post'; import Post from './Post';
import PlaceholderContainer from './PlaceholderContainer'; import PlaceholderContainer from './PlaceholderContainer';
import { determineDBAddress } from '../utils/orbitUtils';
const contract = 'Forum'; const contract = 'Forum';
const getPostMethod = 'getPost'; const getPostMethod = 'getPost';
@ -16,7 +17,8 @@ class PostList extends Component {
this.getBlockchainData = this.getBlockchainData.bind(this); this.getBlockchainData = this.getBlockchainData.bind(this);
this.state = { this.state = {
dataKeys: [] dataKeys: [],
dbAddresses: []
}; };
} }
@ -29,20 +31,31 @@ class PostList extends Component {
} }
getBlockchainData() { getBlockchainData() {
const { dataKeys } = this.state; const { dataKeys, dbAddresses } = this.state;
const { drizzleStatus, postIDs } = this.props; const { drizzleStatus, postIDs, contracts } = this.props;
if (drizzleStatus.initialized) { if (drizzleStatus.initialized) {
const dataKeysShallowCopy = dataKeys.slice(); const dataKeysShallowCopy = dataKeys.slice();
let fetchingNewData = false; let fetchingNewData = false;
postIDs.forEach((postID) => { postIDs.forEach(async (postID) => {
if (!dataKeys[postID]) { if (!dataKeys[postID]) {
dataKeysShallowCopy[postID] = drizzle.contracts[contract].methods[getPostMethod].cacheCall( dataKeysShallowCopy[postID] = drizzle.contracts[contract].methods[getPostMethod].cacheCall(
postID, postID
); );
fetchingNewData = true; fetchingNewData = true;
} }
else if (!dbAddresses[postID]){
const fetchedPostData = contracts[contract][getPostMethod][dataKeys[postID]];
if(fetchedPostData) {
const dbAddress = await determineDBAddress('posts', fetchedPostData.value[0]);
const dbAddressesShallowCopy = dbAddresses.slice();
dbAddressesShallowCopy[postID] = dbAddress;
this.setState({
dbAddresses: dbAddressesShallowCopy
});
}
}
}); });
if (fetchingNewData) { if (fetchingNewData) {
@ -54,7 +67,7 @@ class PostList extends Component {
} }
render() { render() {
const { dataKeys } = this.state; const { dataKeys, dbAddresses } = this.state;
const { postIDs, contracts, focusOnPost, recentToTheTop } = this.props; const { postIDs, contracts, focusOnPost, recentToTheTop } = this.props;
const posts = postIDs.map((postID, index) => { const posts = postIDs.map((postID, index) => {
@ -62,13 +75,16 @@ class PostList extends Component {
if(dataKeys[postID]) if(dataKeys[postID])
fetchedPostData = contracts[contract][getPostMethod][dataKeys[postID]]; fetchedPostData = contracts[contract][getPostMethod][dataKeys[postID]];
if(fetchedPostData) { const dbAddress = dbAddresses[postID];
if(fetchedPostData && dbAddress) {
const userAddress = fetchedPostData.value[0]; //Also works as an Orbit Identity ID
const postData = { const postData = {
userAddress: fetchedPostData.value[1], userAddress,
fullOrbitAddress: `/orbitdb/${fetchedPostData.value[0]}/posts`, fullOrbitAddress: `/orbitdb/${dbAddress}/posts`,
userName: fetchedPostData.value[2], userName: fetchedPostData.value[1],
timestamp: fetchedPostData.value[3]*1000, timestamp: fetchedPostData.value[2]*1000,
topicID: fetchedPostData.value[4] topicID: fetchedPostData.value[3]
}; };
return( return(
<Post <Post

48
app/src/containers/ProfileInformation.js

@ -10,20 +10,13 @@ import ContentLoader from 'react-content-loader';
import UsernameFormContainer from './UsernameFormContainer'; import UsernameFormContainer from './UsernameFormContainer';
import { Table } from 'semantic-ui-react' import { Table } from 'semantic-ui-react'
//TODO: No array needed unless we add more calls
const callsInfo = [ const callsInfo = [
{ {
contract: 'Forum', contract: 'Forum',
method: 'getUserDateOfRegister' method: 'getUserDateOfRegister'
}, { }
contract: 'Forum', ];
method: 'getOrbitDBId'
}, {
contract: 'Forum',
method: 'getOrbitTopicsDB'
}, {
contract: 'Forum',
method: 'getOrbitPostsDB'
}];
class ProfileInformation extends Component { class ProfileInformation extends Component {
constructor(props) { constructor(props) {
@ -50,7 +43,7 @@ class ProfileInformation extends Component {
} }
getBlockchainData() { getBlockchainData() {
const { pageStatus, dateOfRegister, orbitDBId, topicsDBId, postsDBId } = this.state; const { pageStatus, dateOfRegister, topicsDBId, postsDBId } = this.state;
const { drizzleStatus, address, contracts } = this.props; const { drizzleStatus, address, contracts } = this.props;
if (pageStatus === 'initialized' if (pageStatus === 'initialized'
@ -89,37 +82,26 @@ class ProfileInformation extends Component {
}); });
} }
} }
if (orbitDBId === '') {
const transaction = contracts[callsInfo[1].contract][callsInfo[1].method][this.dataKey[1]];
if (transaction) {
this.setState({
orbitDBId: transaction.value
});
}
}
if (topicsDBId === '') { if (topicsDBId === '') {
const transaction = contracts[callsInfo[2].contract][callsInfo[2].method][this.dataKey[2]]; //TODO: can be displayed using determineDBAddress
if (transaction) {
this.setState({ this.setState({
topicsDBId: transaction.value topicsDBId: "TODO"
}); });
}
} }
if (postsDBId === '') { if (postsDBId === '') {
const transaction = contracts[callsInfo[3].contract][callsInfo[3].method][this.dataKey[3]]; //TODO: can be displayed using determineDBAddress
if (transaction) {
this.setState({ this.setState({
postsDBId: transaction.value postsDBId: "TODO"
}); });
} }
} }
} }
}
render() { render() {
const { orbitDBId, topicsDBId, postsDBId, dateOfRegister } = this.state; const { topicsDBId, postsDBId, dateOfRegister } = this.state;
const { avatarUrl, username, address, numberOfTopics, numberOfPosts, self } = this.props; const { avatarUrl, username, address, numberOfTopics, numberOfPosts, self } = this.props;
return ( return (
@ -142,16 +124,6 @@ class ProfileInformation extends Component {
<Table.Cell><strong>Account address:</strong></Table.Cell> <Table.Cell><strong>Account address:</strong></Table.Cell>
<Table.Cell>{address}</Table.Cell> <Table.Cell>{address}</Table.Cell>
</Table.Row> </Table.Row>
<Table.Row>
<Table.Cell><strong>OrbitDB:</strong></Table.Cell>
<Table.Cell>{orbitDBId ? orbitDBId
: <ContentLoader height={5.8} width={300} speed={2}
primaryColor="#b2e8e6" secondaryColor="#00b5ad"
>
<rect x="0" y="0" rx="3" ry="3" width="80" height="5.5" />
</ContentLoader>
}</Table.Cell>
</Table.Row>
<Table.Row> <Table.Row>
<Table.Cell><strong>TopicsDB:</strong></Table.Cell> <Table.Cell><strong>TopicsDB:</strong></Table.Cell>
<Table.Cell>{topicsDBId ? topicsDBId <Table.Cell>{topicsDBId ? topicsDBId

15
app/src/containers/TopicContainer.js

@ -10,6 +10,7 @@ import NewPost from './NewPost';
import FloatingButton from '../components/FloatingButton'; import FloatingButton from '../components/FloatingButton';
import { setNavBarTitle } from '../redux/actions/userInterfaceActions.js'; import { setNavBarTitle } from '../redux/actions/userInterfaceActions.js';
import { determineDBAddress } from '../utils/orbitUtils';
const contract = 'Forum'; const contract = 'Forum';
const getTopicMethod = 'getTopic'; const getTopicMethod = 'getTopic';
@ -95,16 +96,16 @@ class TopicContainer extends Component {
} }
} }
async fetchTopicSubject(orbitDBAddress) { async fetchTopicSubject(userAddress) {
const { topicID } = this.state; const { topicID } = this.state;
const { contracts, user, orbitDB, setNavBarTitle } = this.props; const { user, orbitDB, setNavBarTitle } = this.props;
let orbitData; let orbitData;
if (contracts[contract][getTopicMethod][this.dataKey].value[1] if (userAddress === user.address) {
=== user.address) {
orbitData = orbitDB.topicsDB.get(topicID); orbitData = orbitDB.topicsDB.get(topicID);
} else { } else {
const fullAddress = `/orbitdb/${orbitDBAddress}/topics`; const dbAddress = await determineDBAddress('topics', userAddress);
const fullAddress = `/orbitdb/${dbAddress}/topics`;
const store = await orbitDB.orbitdb.keyvalue(fullAddress); const store = await orbitDB.orbitdb.keyvalue(fullAddress);
await store.load(); await store.load();
@ -152,7 +153,7 @@ class TopicContainer extends Component {
( (
<div> <div>
<PostList <PostList
postIDs={contracts[contract][getTopicMethod][this.dataKey].value[4]} postIDs={contracts[contract][getTopicMethod][this.dataKey].value[3]}
focusOnPost={postFocus focusOnPost={postFocus
? postFocus ? postFocus
: null} : null}
@ -162,7 +163,7 @@ class TopicContainer extends Component {
<NewPost <NewPost
topicID={topicID} topicID={topicID}
subject={topicSubject} subject={topicSubject}
postIndex={contracts[contract][getTopicMethod][this.dataKey].value[4].length} postIndex={contracts[contract][getTopicMethod][this.dataKey].value[3].length}
onCancelClick={() => { this.togglePostingState(); }} onCancelClick={() => { this.togglePostingState(); }}
onPostCreated={() => { this.postCreated(); }} onPostCreated={() => { this.postCreated(); }}
/> />

37
app/src/containers/TopicList.js

@ -5,6 +5,7 @@ import { drizzle } from '../index';
import Topic from './Topic'; import Topic from './Topic';
import PlaceholderContainer from './PlaceholderContainer'; import PlaceholderContainer from './PlaceholderContainer';
import { determineDBAddress } from '../utils/orbitUtils';
const contract = 'Forum'; const contract = 'Forum';
const getTopicMethod = 'getTopic'; const getTopicMethod = 'getTopic';
@ -16,7 +17,8 @@ class TopicList extends Component {
this.getBlockchainData = this.getBlockchainData.bind(this); this.getBlockchainData = this.getBlockchainData.bind(this);
this.state = { this.state = {
dataKeys: [] dataKeys: [],
dbAddresses: []
}; };
} }
@ -29,19 +31,30 @@ class TopicList extends Component {
} }
getBlockchainData() { getBlockchainData() {
const { dataKeys } = this.state; const { dataKeys, dbAddresses } = this.state;
const { drizzleStatus, topicIDs } = this.props; const { drizzleStatus, topicIDs, contracts } = this.props;
if (drizzleStatus.initialized) { if (drizzleStatus.initialized) {
const dataKeysShallowCopy = dataKeys.slice(); const dataKeysShallowCopy = dataKeys.slice();
let fetchingNewData = false; let fetchingNewData = false;
topicIDs.forEach((topicID) => { topicIDs.forEach(async (topicID) => {
if (!dataKeys[topicID]) { if (!dataKeys[topicID]) {
dataKeysShallowCopy[topicID] = drizzle.contracts[contract].methods[getTopicMethod] dataKeysShallowCopy[topicID] = drizzle.contracts[contract].methods[getTopicMethod]
.cacheCall(topicID); .cacheCall(topicID);
fetchingNewData = true; fetchingNewData = true;
} }
else if (!dbAddresses[topicID]){
const fetchedTopicData = contracts[contract][getTopicMethod][dataKeys[topicID]];
if(fetchedTopicData) {
const dbAddress = await determineDBAddress('topics', fetchedTopicData.value[0]);
const dbAddressesShallowCopy = dbAddresses.slice();
dbAddressesShallowCopy[topicID] = dbAddress;
this.setState({
dbAddresses: dbAddressesShallowCopy
});
}
}
}); });
if (fetchingNewData) { if (fetchingNewData) {
@ -53,7 +66,7 @@ class TopicList extends Component {
} }
render() { render() {
const { dataKeys } = this.state; const { dataKeys, dbAddresses } = this.state;
const { topicIDs, contracts } = this.props; const { topicIDs, contracts } = this.props;
const topics = topicIDs.map(topicID => { const topics = topicIDs.map(topicID => {
@ -61,13 +74,15 @@ class TopicList extends Component {
if(dataKeys[topicID]) if(dataKeys[topicID])
fetchedTopicData = contracts[contract][getTopicMethod][dataKeys[topicID]]; fetchedTopicData = contracts[contract][getTopicMethod][dataKeys[topicID]];
if(fetchedTopicData) { const dbAddress = dbAddresses[topicID];
if(fetchedTopicData && dbAddress) {
const userAddress = fetchedTopicData.value[0]; //Also works as an Orbit Identity ID
const topicData = { const topicData = {
userAddress: fetchedTopicData.value[1], userAddress,
fullOrbitAddress: `/orbitdb/${fetchedTopicData.value[0]}/topics`, fullOrbitAddress: `/orbitdb/${dbAddress}/topics`,
userName: fetchedTopicData.value[2], userName: fetchedTopicData.value[1],
timestamp: fetchedTopicData.value[3]*1000, timestamp: fetchedTopicData.value[2]*1000,
numberOfReplies: fetchedTopicData.value[4].length numberOfReplies: fetchedTopicData.value[3].length
}; };
return( return(
<Topic <Topic

25
app/src/containers/UsernameFormContainer.js

@ -79,33 +79,12 @@ class UsernameFormContainer extends Component {
this.setState({ this.setState({
signingUp: true signingUp: true
}); });
const { const { orbitdb,topicsDB,postsDB } = await createDatabases();
identityId,
identityPublicKey,
identityPrivateKey,
orbitdb,
orbitPublicKey,
orbitPrivateKey,
topicsDB,
postsDB
} = await createDatabases();
dispatch( dispatch(
updateDatabases(DATABASES_CREATED, orbitdb, topicsDB, postsDB), updateDatabases(DATABASES_CREATED, orbitdb, topicsDB, postsDB),
); );
this.stackId = drizzle.contracts[contract].methods[signUpMethod].cacheSend( this.stackId = drizzle.contracts[contract].methods[signUpMethod].cacheSend(
...[ ...[usernameInput], { from: account }
usernameInput,
identityId,
identityPublicKey,
identityPrivateKey,
orbitdb.id,
orbitPublicKey,
orbitPrivateKey,
topicsDB,
postsDB
], {
from: account
},
); );
} }
this.setState({ this.setState({

20
app/src/redux/sagas/orbitSaga.js

@ -2,7 +2,7 @@ import { all, call, put, select, take, takeEvery, takeLatest } from 'redux-saga/
import isEqual from 'lodash.isequal'; import isEqual from 'lodash.isequal';
import { forumContract, getCurrentAccount } from './web3UtilsSaga'; import { forumContract, getCurrentAccount } from './web3UtilsSaga';
import { import {
createTempDatabases, createDatabases,
loadDatabases, loadDatabases,
orbitSagaOpen orbitSagaOpen
} from '../../utils/orbitUtils'; } from '../../utils/orbitUtils';
@ -31,26 +31,12 @@ function* getOrbitDBInfo() {
address: account address: account
}); });
if (callResult) { if (callResult) {
const txObj2 = yield call(forumContract.methods.getOrbitIdentityInfo, yield call(loadDatabases);
...[account]);
const orbitIdentityInfo = yield call(txObj2.call, {
address: account
});
const txObj3 = yield call(forumContract.methods.getOrbitDBInfo,
...[account]);
const orbitDBInfo = yield call(txObj3.call, {
address: account
});
yield call(loadDatabases, orbitIdentityInfo[0], orbitIdentityInfo[1],
orbitIdentityInfo[2],
orbitDBInfo[0], orbitDBInfo[1], orbitDBInfo[2], orbitDBInfo[3],
orbitDBInfo[4]);
} else { } else {
const orbit = yield select(state => state.orbit); const orbit = yield select(state => state.orbit);
if(!orbit.ready){ if(!orbit.ready){
const { orbitdb, topicsDB, postsDB } = yield call(createTempDatabases); const { orbitdb, topicsDB, postsDB } = yield call(createDatabases);
yield put(updateDatabases(DATABASES_CREATED, orbitdb, topicsDB, postsDB )); yield put(updateDatabases(DATABASES_CREATED, orbitdb, topicsDB, postsDB ));
console.debug("Created temporary databases.");
} }
} }
latestAccount = account; latestAccount = account;

3
app/src/redux/sagas/transactionsSaga.js

@ -4,17 +4,14 @@ import { drizzle } from '../../index';
import { orbitSagaPut } from '../../utils/orbitUtils'; import { orbitSagaPut } from '../../utils/orbitUtils';
import { WEB3_UTILS_SAGA_INITIALIZED } from '../actions/web3UtilsActions'; import { WEB3_UTILS_SAGA_INITIALIZED } from '../actions/web3UtilsActions';
import { CONTRACT_EVENT_FIRED } from './eventSaga'; import { CONTRACT_EVENT_FIRED } from './eventSaga';
import { getCurrentAccount } from './web3UtilsSaga';
const transactionsHistory = Object.create(null); const transactionsHistory = Object.create(null);
function* initTransaction(action) { function* initTransaction(action) {
action.transactionDescriptor.params.from = getCurrentAccount();
const dataKey = drizzle.contracts[action.transactionDescriptor.contract] const dataKey = drizzle.contracts[action.transactionDescriptor.contract]
.methods[action.transactionDescriptor.method].cacheSend( .methods[action.transactionDescriptor.method].cacheSend(
...(action.transactionDescriptor.params) ...(action.transactionDescriptor.params)
); );
transactionsHistory[dataKey] = action; transactionsHistory[dataKey] = action;
transactionsHistory[dataKey].state = 'initialized'; transactionsHistory[dataKey].state = 'initialized';
} }

20
app/src/utils/levelUtils.js

@ -1,20 +0,0 @@
import level from 'level'
const db = level('./orbitdb/identity/identitykeys');
async function getPrivateKey(id){
try{
const keyPair = await db.get(id);
return JSON.parse(keyPair).privateKey;
} catch (err) {
if (err && err.notFound)
console.error("LevelDB: Private Key not found!");
throw err;
}
}
async function setKeyPair(id, publicKey, privateKey){
await db.put(id,JSON.stringify({publicKey: publicKey, privateKey: privateKey}));
}
export { getPrivateKey, setKeyPair }

91
app/src/utils/orbitUtils.js

@ -5,7 +5,6 @@ import store from '../redux/store';
import { DATABASES_LOADED, IPFS_INITIALIZED, updateDatabases } from '../redux/actions/orbitActions'; import { DATABASES_LOADED, IPFS_INITIALIZED, updateDatabases } from '../redux/actions/orbitActions';
import ipfsOptions from '../config/ipfsOptions'; import ipfsOptions from '../config/ipfsOptions';
import EthereumIdentityProvider from './EthereumIdentityProvider'; import EthereumIdentityProvider from './EthereumIdentityProvider';
import { getPrivateKey, setKeyPair } from './levelUtils';
function initIPFS() { function initIPFS() {
Identities.addIdentityProvider(EthereumIdentityProvider); Identities.addIdentityProvider(EthereumIdentityProvider);
@ -23,63 +22,17 @@ function initIPFS() {
}); });
} }
async function createTempDatabases() {
console.debug('Creating temporary databases...');
const ipfs = getIPFS();
const identity = await Identities.createIdentity({type: 'ethereum'});
const orbitdb = await OrbitDB.createInstance(ipfs, {identity});
console.dir(orbitdb)
const topicsDB = await orbitdb.keyvalue('topics');
const postsDB = await orbitdb.keyvalue('posts');
return { orbitdb, topicsDB, postsDB };
}
async function createDatabases() { async function createDatabases() {
console.debug('Creating databases...'); console.debug('Creating databases...');
const ipfs = getIPFS(); const databases = await createDBs();
const identity = await Identities.createIdentity({type: 'ethereum'}); console.debug('Databases created successfully.');
const orbitdb = await OrbitDB.createInstance(ipfs, {identity}); return databases;
const options = {
// Give write access to ourselves
accessController: {
write: ['*']
}
};
const topicsDB = await orbitdb.keyvalue('topics', options);
const postsDB = await orbitdb.keyvalue('posts', options);
const privateKey = await getPrivateKey(identity.id);
return {
identityId: identity.id,
identityPublicKey: identity.publicKey,
identityPrivateKey: privateKey,
orbitdb: orbitdb,
orbitPublicKey: "eeeee",
orbitPrivateKey: "fffffff",
topicsDB: topicsDB.address.root,
postsDB: postsDB.address.root
};
} }
async function loadDatabases(identityId, identityPublicKey, identityPrivateKey, async function loadDatabases() {
orbitId, orbitPublicKey, orbitPrivateKey,
topicsDBId, postsDBId) {
console.debug('Loading databases...'); console.debug('Loading databases...');
const ipfs = getIPFS(); const { orbitdb, topicsDB, postsDB } = await createDBs();
await setKeyPair(identityId, identityPublicKey, identityPrivateKey);
const identity = await Identities.createIdentity({type: 'ethereum' });
const orbitdb = await OrbitDB.createInstance(ipfs, {identity});
console.dir(orbitdb)
const topicsDB = await orbitdb.keyvalue('topics')
.catch((error) => console.error(`TopicsDB init error: ${error}`));
console.dir(topicsDB)
const postsDB = await orbitdb.keyvalue('posts')
.catch((error) => console.error(`PostsDB init error: ${error}`));
console.dir(topicsDB)
await topicsDB.load().catch((error) => console.error(`TopicsDB loading error: ${error}`)); await topicsDB.load().catch((error) => console.error(`TopicsDB loading error: ${error}`));
await postsDB.load().catch((error) => console.error(`PostsDB loading error: ${error}`)); await postsDB.load().catch((error) => console.error(`PostsDB loading error: ${error}`));
@ -101,10 +54,22 @@ async function loadDatabases(identityId, identityPublicKey, identityPrivateKey,
store.dispatch(updateDatabases(DATABASES_LOADED, orbitdb, topicsDB, postsDB)); store.dispatch(updateDatabases(DATABASES_LOADED, orbitdb, topicsDB, postsDB));
} }
async function determineDBAddress(name, identityId){
return (await getOrbitDB().determineAddress(name, 'keyvalue', {
accessController: {
write: [identityId]}
}
)).root;
}
function getIPFS() { function getIPFS() {
return store.getState().orbit.ipfs; return store.getState().orbit.ipfs;
} }
function getOrbitDB() {
return store.getState().orbit.orbitdb;
}
async function orbitSagaPut(db, key, value) { async function orbitSagaPut(db, key, value) {
await db.put(key, value).catch((error) => console.error(`Orbit put error: ${error}`)); await db.put(key, value).catch((error) => console.error(`Orbit put error: ${error}`));
} }
@ -122,4 +87,24 @@ async function orbitSagaOpen(orbitdb, address) {
return store; return store;
} }
export { initIPFS, createTempDatabases, createDatabases, loadDatabases, orbitSagaPut, orbitSagaOpen }; async function createDBs(){
const ipfs = getIPFS();
const identity = await Identities.createIdentity({type: 'ethereum'});
const orbitdb = await OrbitDB.createInstance(ipfs, {identity});
const topicsDB = await orbitdb.keyvalue('topics')
.catch((error) => console.error(`TopicsDB init error: ${error}`));
const postsDB = await orbitdb.keyvalue('posts')
.catch((error) => console.error(`PostsDB init error: ${error}`));
return { orbitdb, topicsDB, postsDB };
}
export {
initIPFS,
createDatabases,
loadDatabases,
orbitSagaPut,
orbitSagaOpen,
determineDBAddress
};

92
contracts/Forum.sol

@ -5,7 +5,6 @@ contract Forum {
//----------------------------------------USER---------------------------------------- //----------------------------------------USER----------------------------------------
struct User { struct User {
string username; // TODO: set an upper bound instead of arbitrary string string username; // TODO: set an upper bound instead of arbitrary string
OrbitDB orbitdb;
uint[] topicIDs; // IDs of the topics the user created uint[] topicIDs; // IDs of the topics the user created
uint[] postIDs; // IDs of the posts the user created uint[] postIDs; // IDs of the posts the user created
uint timestamp; uint timestamp;
@ -18,15 +17,10 @@ contract Forum {
event UserSignedUp(string username, address userAddress); event UserSignedUp(string username, address userAddress);
event UsernameUpdated(string newName, string oldName,address userAddress); event UsernameUpdated(string newName, string oldName,address userAddress);
function signUp(string memory username, string memory orbitIdentityId, function signUp(string memory username) public returns (bool) {
string memory orbitIdentityPublicKey, string memory orbitIdentityPrivateKey,
string memory orbitId, string memory orbitPublicKey, string memory orbitPrivateKey,
string memory orbitTopicsDB, string memory orbitPostsDB) public returns (bool) {
require (!hasUserSignedUp(msg.sender), "User has already signed up."); require (!hasUserSignedUp(msg.sender), "User has already signed up.");
require(!isUserNameTaken(username), "Username is already taken."); require(!isUserNameTaken(username), "Username is already taken.");
users[msg.sender] = User(username, users[msg.sender] = User(username,
OrbitDB(orbitIdentityId, orbitIdentityPublicKey, orbitIdentityPrivateKey,
orbitId, orbitPublicKey, orbitPrivateKey, orbitTopicsDB, orbitPostsDB),
new uint[](0), new uint[](0), block.timestamp, true); new uint[](0), new uint[](0), block.timestamp, true);
userAddresses[username] = msg.sender; userAddresses[username] = msg.sender;
emit UserSignedUp(username, msg.sender); emit UserSignedUp(username, msg.sender);
@ -78,82 +72,6 @@ contract Forum {
return users[userAddress].timestamp; return users[userAddress].timestamp;
} }
//----------------------------------------OrbitDB----------------------------------------
// TODO: set upper bounds to strings (instead of being of arbitrary length)
// TODO: not sure if topicsDB//postsDB are actually needed
struct OrbitDB {
string identityId;
string identityPublicKey;
string identityPrivateKey;
string orbitId;
string orbitPublicKey;
string orbitPrivateKey;
string topicsDB;
string postsDB;
}
function getOrbitIdentityId(address userAddress) public view returns (string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return users[userAddress].orbitdb.identityId;
}
function getOrbitIdentityPublicKey(address userAddress) public view returns (string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return users[userAddress].orbitdb.identityPublicKey;
}
function getOrbitIdentityPrivateKey(address userAddress) public view returns (string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return users[userAddress].orbitdb.identityPrivateKey;
}
function getOrbitDBId(address userAddress) public view returns (string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return users[userAddress].orbitdb.orbitId;
}
function getOrbitPublicKey(address userAddress) public view returns (string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return users[userAddress].orbitdb.orbitPublicKey;
}
//TODO: encrypt using Metamask in the future
function getOrbitPrivateKey(address userAddress) public view returns (string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return users[userAddress].orbitdb.orbitPrivateKey;
}
function getOrbitTopicsDB(address userAddress) public view returns (string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return users[userAddress].orbitdb.topicsDB;
}
function getOrbitPostsDB(address userAddress) public view returns (string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return users[userAddress].orbitdb.postsDB;
}
function getOrbitIdentityInfo(address userAddress) public view returns (string memory, string memory, string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return (
users[userAddress].orbitdb.identityId,
users[userAddress].orbitdb.identityPublicKey,
users[userAddress].orbitdb.identityPrivateKey
);
}
function getOrbitDBInfo(address userAddress) public view returns (string memory, string memory,
string memory, string memory, string memory) {
require (hasUserSignedUp(userAddress), "User hasn't signed up.");
return (
users[userAddress].orbitdb.orbitId,
users[userAddress].orbitdb.orbitPublicKey,
users[userAddress].orbitdb.orbitPrivateKey,
users[userAddress].orbitdb.topicsDB,
users[userAddress].orbitdb.postsDB
);
}
//----------------------------------------POSTING---------------------------------------- //----------------------------------------POSTING----------------------------------------
struct Topic { struct Topic {
@ -211,10 +129,10 @@ contract Forum {
return numTopics; return numTopics;
} }
function getTopic(uint topicID) public view returns (string memory, address, string memory, uint, uint[] memory) { function getTopic(uint topicID) public view returns (address, string memory, uint, uint[] memory) {
//require(hasUserSignedUp(msg.sender)); needed? //require(hasUserSignedUp(msg.sender)); needed?
require(topicID<numTopics); require(topicID<numTopics);
return (getOrbitTopicsDB(topics[topicID].author), return (
topics[topicID].author, topics[topicID].author,
users[topics[topicID].author].username, users[topics[topicID].author].username,
topics[topicID].timestamp, topics[topicID].timestamp,
@ -227,10 +145,10 @@ contract Forum {
return topics[topicID].postIDs; return topics[topicID].postIDs;
} }
function getPost(uint postID) public view returns (string memory, address, string memory, uint, uint) { function getPost(uint postID) public view returns (address, string memory, uint, uint) {
//require(hasUserSignedUp(msg.sender)); needed? //require(hasUserSignedUp(msg.sender)); needed?
require(postID<numPosts); require(postID<numPosts);
return (getOrbitPostsDB(posts[postID].author), return (
posts[postID].author, posts[postID].author,
users[posts[postID].author].username, users[posts[postID].author].username,
posts[postID].timestamp, posts[postID].timestamp,

Loading…
Cancel
Save