diff --git a/tinpi/contracts/OpenSpacesConference.sol b/tinpi/contracts/OpenSpacesConference.sol index a75af32..399e423 100644 --- a/tinpi/contracts/OpenSpacesConference.sol +++ b/tinpi/contracts/OpenSpacesConference.sol @@ -34,6 +34,34 @@ contract OpenSpacesConference { uint[] _topicsVoted ); + event CompetitionCreateLog( + uint id, + string name, + string description, + uint[] topicIds, + uint minVotes, + uint maxVotes, + address moderator, + bool active + ); + + event CompetitionVoteLog( + uint count, + uint totalVotes, + bool active + ); + + event CompetitionFetchLog( + uint id, + string name, + uint[] topicIds, + uint minVotes, + uint maxVotes, + address moderator, + bool active, + uint[] topicVotes + ); + event VoteLog(uint voteCount); struct Topic { @@ -52,13 +80,27 @@ contract OpenSpacesConference { uint[] topicsVoted; } + struct Competition { + uint id; + string name; + string description; + uint[] topicIds; + uint minVotes; + uint maxVotes; + address moderator; + bool active; + mapping(uint => uint) topicVotes; + } + uint lastTopicId = 0; uint lastParticipantId = 0; + uint lastCompetitionId = 0; mapping(uint => Topic) topics; mapping(uint => Participant) participants; + mapping(uint => Competition) competitions; - function voteForTopic(uint topicId, uint participantId) - public { + function expressInterest(uint topicId, uint participantId) + public { address voter = msg.sender; Participant p = participants[participantId]; participantId = p.id; @@ -78,11 +120,57 @@ contract OpenSpacesConference { } } +// function countTotalVotes(Competition c) returns (uint _count) { +// _count = 0; +// for (uint j = 0; j < c.topicIds.length; j++) { +// _count = _count + c.topicVotes[c.topicIds[j]]; +// } +// } + + function voteInCompetition(uint topicId, uint participantId, uint competitionId) + public { + address voter = msg.sender; + + Participant p = participants[participantId]; + participantId = p.id; + if (p.voterAddr != voter) { + return; + } + Competition c = competitions[competitionId]; + uint votes = c.topicVotes[topicId]; + c.topicVotes[topicId] = votes + 1; + uint totalVotes = 0; + for (uint j = 0; j < c.topicIds.length; j++) { + totalVotes = totalVotes + c.topicVotes[c.topicIds[j]]; + } + bool _active = true; + if (totalVotes >= c.maxVotes) { + _active = false; + } + c.active = _active; + CompetitionVoteLog(c.topicVotes[topicId], totalVotes, _active); + + } + + + function addCompetition( + string name, string description, uint[] topicIds, uint minVotes, uint maxVotes) + public returns (uint competitionId) { + address moderator = msg.sender; + competitionId = lastCompetitionId++; + Competition memory c = Competition( + competitionId, name, description, topicIds, minVotes, maxVotes, moderator, true); + competitions[competitionId] = c; + CompetitionCreateLog( + competitionId, name, description, topicIds, minVotes, maxVotes, moderator, true); + } + function addParticipant(string name, string interests) public returns (uint participantId) { address creator = msg.sender; participantId = lastParticipantId++; - participants[participantId] = Participant(participantId, name, interests, creator, new uint[](0)); + participants[participantId] = Participant( + participantId, name, interests, creator, new uint[](0)); ParticipantCreateLog(participantId, name, interests); } @@ -90,7 +178,6 @@ contract OpenSpacesConference { public returns (uint topicId) { address creator = msg.sender; - topicId = lastTopicId++; topics[topicId] = Topic( topicId, @@ -99,8 +186,6 @@ contract OpenSpacesConference { creator, new address[](0) ); - - TopicCreateLog(topicId, name, description, creator, 0); } @@ -115,7 +200,6 @@ contract OpenSpacesConference { public constant returns (uint _id, string _name, string _desc, address _creator, uint _votes) { - _id = topics[idx].id; _name = topics[idx].name; _desc = topics[idx].description; @@ -131,7 +215,6 @@ contract OpenSpacesConference { public constant returns (uint _id, string _name, string _interests, address _voteAddr, uint[] _topicsVoted) { - _id = participants[idx].id; _name = participants[idx].name; _interests = participants[idx].interests; @@ -140,10 +223,52 @@ contract OpenSpacesConference { ParticipantFetchLog(_id, _name, _interests, _voteAddr, _topicsVoted); } + + function getCompetition(uint idx) + public constant + returns ( + uint _id, string _name, uint[] _topicIds, + uint _minVotes, uint _maxVotes, address _moderator, bool _active, + uint[] _topicVotes) + { + Competition c = competitions[idx]; + _id = c.id; + _name = c.name; + _topicIds = c.topicIds; + _minVotes = c.minVotes; + _maxVotes = c.maxVotes; + _moderator = c.moderator; + _active = c.active; + + uint[] tvs; + tvs.length = 0; + for (uint i = 0; i < _topicIds.length; i++) { + tvs.length += 1; + tvs[i] = (c.topicVotes[_topicIds[i]]); + } + _topicVotes = tvs; + CompetitionFetchLog(_id, _name, _topicIds, _minVotes, _maxVotes, _moderator, _active, _topicVotes); + + } + function getTopicsCount() public constant returns (uint _count) { TopicCountLog(lastTopicId); _count = lastTopicId; } + + + function getParticipantsCount() + public constant + returns (uint _count) { + _count = lastParticipantId; + } + + + function getCompetitionsCount() + public constant + returns (uint _count) { + _count = lastCompetitionId; + } } diff --git a/tinpi/test/Voting.test.js b/tinpi/test/Voting.test.js index d55261e..9b953c6 100644 --- a/tinpi/test/Voting.test.js +++ b/tinpi/test/Voting.test.js @@ -15,197 +15,348 @@ beforeEach(async () => { // Use the first account found for tests conference = await new web3.eth.Contract(JSON.parse(interface)) .deploy({data: bytecode, arguments: []}) - .send({from: accounts[0], gas: 2000000, gasPrice: '5'}); + .send({from: accounts[0], gas: 3000000, gasPrice: '1'}); conference.setProvider(provider); - await conference - .methods - .addTopic( - "Test Topic", - "Test Topic Info") - .send({from: accounts[0], gas: 3000000}); - - - await conference - .methods - .addParticipant( - "First Last", - "solc,skiing") - .send({from: accounts[0], gas: 3000000}); }); describe('Create topics and participants and votes', () => { it('deploys a contract', () => { assert.ok(conference.options.address); + }); - it('votes for topic', () => { - assert - .ok(conference - .methods - .voteForTopic(0, 0) - .send({from: accounts[0], gas: 3000000}) - .on('transactionHash', function (hash) { - }) - .on('confirmation', function (confirmationNumber, receipt) { - }) - .on('receipt', function (receipt) { - const retVals = receipt.events.VoteLog.returnValues; - console.log("Vote retvals: ", retVals); - assert.equal(retVals.voteCount, 1); - }) - .catch(e => { - console.log(e); - assert.fail("", e, "Error voting"); - })) + it('fetches competition with votes', async () => { + + await conference + .methods + .addTopic( + "Test Topic", + "Test Topic Info") + .send({from: accounts[0], gas: 3000000}); + + + await conference + .methods + .addParticipant( + "First Last", + "solc,skiing") + .send({from: accounts[0], gas: 3000000}); + + + await conference + .methods + .addParticipant( + "First2 Last2", + "clojure,datomic") + .send({from: accounts[1], gas: 3000000}); + await conference + .methods + .addParticipant( + "First3 Last3", + "scala,kotlin") + .send({from: accounts[2], gas: 3000000}); + + + // Create competition with 2 topics + const addCompReceipt1 = await conference + .methods + .addCompetition( + "Monday Morning Discussion", + "Desc Monday Morning", + [0, 1], + 2, + 3) + .send({from: accounts[0], gas: 3000000}); + + // Person 1 Votes for Topic 1 + const voteCompReceipt1 = await conference + .methods + .voteInCompetition(0, 0, 0) + .send({from: accounts[0], gas: 3000000}); + + // Fetch competition + const fetchCompReceipt1 = await conference + .methods + .getCompetition(0) + .send({from: accounts[0], gas: 3000000}); + + + // console.log("Fetched comp first: ", fetchCompReceipt1.events.CompetitionFetchLog.returnValues); + assert.equal( + fetchCompReceipt1.events.CompetitionFetchLog.returnValues.id, + 0); + // Assert 1 vote for Topic 1 + assert.equal( + fetchCompReceipt1.events.CompetitionFetchLog.returnValues.topicVotes[0], + 1); + + + // Person 2 votes for Topic 1 + const voteCompReceipt2 = await conference + .methods + .voteInCompetition(0, 1, 0) + .send({from: accounts[1], gas: 3000000}); + + console.log("Vote receipt second: ", voteCompReceipt2.events.CompetitionVoteLog.returnValues); + //CompetitionVoteLog(votes + 1, totalVotes, c.active); + assert.equal( + voteCompReceipt2.events.CompetitionVoteLog.returnValues.count, + 2); + + + const fetchCompReceipt2 = await conference + .methods + .getCompetition(0) + .send({from: accounts[0], gas: 3000000}); + // console.log("Fetched comp second: ", fetchCompReceipt2.events.CompetitionFetchLog.returnValues); + + assert.equal( + fetchCompReceipt2.events.CompetitionFetchLog.returnValues.id, + 0); + // Now Topic 2 has 2 votes + assert.equal( + fetchCompReceipt2.events.CompetitionFetchLog.returnValues.topicVotes[0], + 2); + + // Person 3 votes for Topic 1 + const voteCompReceipt3 = await conference + .methods + .voteInCompetition(0, 2, 0) + .send({from: accounts[2], gas: 3000000}); + console.log("vote3: ", voteCompReceipt3.events.CompetitionVoteLog.returnValues); + + const fetchCompReceipt3 = await conference + .methods + .getCompetition(0) + .send({from: accounts[0], gas: 3000000}); + console.log("Fetched comp third: ", fetchCompReceipt2.events.CompetitionFetchLog.returnValues); + assert.equal( + fetchCompReceipt3.events.CompetitionFetchLog.returnValues.topicVotes[0], + 3); + assert.equal( + fetchCompReceipt1.events.CompetitionFetchLog.returnValues.active, + true); + assert.equal( + fetchCompReceipt2.events.CompetitionFetchLog.returnValues.active, + true); + assert.equal( + fetchCompReceipt3.events.CompetitionFetchLog.returnValues.active, + false); + }); - it('votes for topic are allowed only by address owner', () => { - assert - .ok(conference - .methods - .voteForTopic(0, 0) - .send({from: accounts[1], gas: 3000000}) - .on('transactionHash', function (hash) { - }) - .on('confirmation', function (confirmationNumber, receipt) { - }) - .on('receipt', function (receipt) { - const retVals = receipt.events.VoteLog.returnValues; - console.log("Vote retvals for vote not allowed: ", retVals); - assert.equal(retVals.voteCount, 0); - }) - .catch(e => { - console.log(e); - assert.fail("", e, "Error voting"); - })) + it('adds competition', async () => { + const compReceipt1 = await conference + .methods + .addCompetition( + "Monday Morning Discussion", + "Desc Monday Morning", + [0, 1], + 2, + 10) + .send({from: accounts[0], gas: 3000000}); + assert.equal( + compReceipt1.events.CompetitionCreateLog.returnValues.name, + "Monday Morning Discussion"); }); - it('adds a participant', () => { - assert - .ok(conference - .methods - .addParticipant( - "First2 Last2", - "clojure,datomic") - .send({from: accounts[0], gas: 3000000}) - .on('transactionHash', function (hash) { - }) - .on('confirmation', function (confirmationNumber, receipt) { - }) - .on('receipt', function (receipt) { - const retVals = receipt.events.ParticipantCreateLog.returnValues; - assert.equal(retVals._name, "First2 Last2"); - assert.equal(retVals._interests, "clojure,datomic"); - }) - .catch(e => { - console.log(e); - assert.fail("", e, "Error creating participant"); - })) + it('e2e', async () => { + await conference + .methods + .addParticipant( + "First Last", + "solc,skiing") + .send({from: accounts[0], gas: 3000000}); + + + await conference + .methods + .addParticipant( + "First2 Last2", + "clojure,datomic") + .send({from: accounts[1], gas: 3000000}); + + await conference + .methods + .addParticipant( + "First3 Last3", + "kotlin,scala") + .send({from: accounts[2], gas: 3000000}); + + const topicReceipt1 = await conference + .methods + .addTopic( + "E2E Topic 1", + "E2E Desc 1") + .send({from: accounts[0], gas: 3000000}); + + + const topicReceipt2 = await conference + .methods + .addTopic( + "E2E Topic 2", + "E2E Desc 2") + .send({from: accounts[1], gas: 3000000}); + + + const topicReceipt3 = await conference + .methods + .addTopic( + "E2E Topic 3", + "E2E Desc 3") + .send({from: accounts[2], gas: 3000000}); + + + const voteReceipt1 = await conference + .methods + .expressInterest(0, 0) + .send({from: accounts[0], gas: 3000000}); + + + const voteReceipt2 = await conference + .methods + .expressInterest(1, 1) + .send({from: accounts[1], gas: 3000000}); + + + const voteReceipt3 = await conference + .methods + .expressInterest(1, 2) + .send({from: accounts[2], gas: 3000000}); + + const retVals1 = voteReceipt1.events.VoteLog.returnValues; + const retVals2 = voteReceipt2.events.VoteLog.returnValues; + const retVals3 = voteReceipt3.events.VoteLog.returnValues; + console.log("Vote retvals: ", retVals1); + assert.equal(retVals1.voteCount, 1); + assert.equal(retVals2.voteCount, 1); + assert.equal(retVals3.voteCount, 2); + + }); + it('votes for topic', async () => { + await conference + .methods + .addTopic( + "Test Topic", + "Test Topic Info") + .send({from: accounts[0], gas: 3000000}); + await conference + .methods + .addParticipant( + "First Last", + "solc,skiing") + .send({from: accounts[0], gas: 3000000}); + + const receipt = await conference + .methods + .expressInterest(0, 0) + .send({from: accounts[0], gas: 3000000}); + const retVals = receipt.events.VoteLog.returnValues; + console.log("Express interest retvals: ", retVals); + assert.equal(retVals.voteCount, 1); + }); + it('votes for topic are allowed only by address owner', async () => { + + const receipt = await conference + .methods + .expressInterest(0, 0) + .send({from: accounts[1], gas: 3000000}); + const retVals = receipt.events.VoteLog.returnValues; + console.log("Vote retvals for vote not allowed: ", retVals); + assert.equal(retVals.voteCount, 0); }); - it('fetches participant', () => { - assert - .ok(conference - .methods - .getParticipant( - 0) - .send({from: accounts[0], gas: 3000000}) - .on('transactionHash', function (hash) { - // console.log("Tx Hash:", hash); - }) - .on('confirmation', function (confirmationNumber, receipt) { - // console.log("Confirmation: ", confirmationNumber, receipt); - }) - .on('receipt', function (receipt) { - const retVals = receipt.events.ParticipantFetchLog.returnValues; - - assert.equal(retVals._name, "First Last", "Created participant name"); - }) - .catch(e => console.log(e)) - ); + it('adds a participant', async () => { + const receipt = await conference + .methods + .addParticipant( + "First2 Last2", + "clojure,datomic") + .send({from: accounts[0], gas: 3000000}); + const retVals = receipt.events.ParticipantCreateLog.returnValues; + assert.equal(retVals._name, "First2 Last2"); + assert.equal(retVals._interests, "clojure,datomic"); + + }); + it('fetches participant', async () => { + await conference + .methods + .addParticipant( + "First Last", + "solc,skiing") + .send({from: accounts[0], gas: 3000000}); + const receipt = await conference + .methods + .getParticipant( + 0) + .send({from: accounts[0], gas: 3000000}); + const retVals = receipt.events.ParticipantFetchLog.returnValues; + assert.equal(retVals._name, "First Last", "Created participant name"); }); - it('adds a topic', () => { - assert - .ok(conference - .methods - .addTopic( - "Test Topic 2", - "Topic Descrip 2") - .send({from: accounts[0], gas: 3000000}) - .on('transactionHash', function (hash) { - }) - .on('confirmation', function (confirmationNumber, receipt) { - }) - .on('receipt', function (receipt) { - const retVals = receipt.events.TopicCreateLog.returnValues; - console.log( - "0Receipt: ", - JSON.stringify(retVals)); - assert.equal(retVals._name, "Test Topic 2"); - assert.equal(retVals._desc, "Topic Descrip 2"); - }) - .catch(e => { - console.log(e); - assert.fail("", e, "Error creating topic"); - })) + it('adds a topic', async () => { + const receipt = await conference + .methods + .addTopic( + "Test Topic 2", + "Topic Descrip 2") + .send({from: accounts[0], gas: 3000000}); + const retVals = receipt.events.TopicCreateLog.returnValues; + console.log( + "0Receipt: ", + JSON.stringify(retVals)); + assert.equal(retVals._name, "Test Topic 2"); + assert.equal(retVals._desc, "Topic Descrip 2"); }); - it('fetches topic ids', () => { - assert - .ok(conference - .methods - .getTopicId( - 0) - .send({from: accounts[0], gas: 3000000}) - .on('transactionHash', function (hash) { - }) - .on('confirmation', function (confirmationNumber, receipt) { - }) - .on('receipt', function (receipt) { - const retVals = receipt.events.TopicIdLog.returnValues; - console.log( - "1Receipt: ", - JSON.stringify(retVals)); - assert.equal(retVals._topicId, 0); - }) - .catch(e => console.log(e)) - ); + it('fetches topic ids', async () => { + await conference + .methods + .addTopic( + "Test Topic", + "Test Topic Info") + .send({from: accounts[0], gas: 3000000}); + + const receipt = await conference + .methods + .getTopicId( + 0) + .send({from: accounts[0], gas: 3000000}); + const retVals = receipt.events.TopicIdLog.returnValues; + console.log( + "1Receipt: ", + JSON.stringify(retVals)); + assert.equal(retVals._topicId, 0); }); - it('fetches topic', () => { - assert - .ok(conference - .methods - .getTopic( - 0) - .send({from: accounts[0], gas: 3000000}) - .on('transactionHash', function (hash) { - // console.log("Tx Hash:", hash); - }) - .on('confirmation', function (confirmationNumber, receipt) { - // console.log("Confirmation: ", confirmationNumber, receipt); - }) - .on('receipt', function (receipt) { - const retVals = receipt.events.TopicFetchLog.returnValues; - console.log( - "2Receipt: ", - JSON.stringify(retVals)); - assert.equal(retVals._name, "Test Topic", "Created topic name"); - }) - .catch(e => console.log(e)) - ); + it('fetches topic', async () => { + await conference + .methods + .addTopic( + "Test Topic", + "Test Topic Info") + .send({from: accounts[0], gas: 3000000}); + + const receipt = await conference + .methods + .getTopic( + 0) + .send({from: accounts[0], gas: 3000000}); + const retVals = receipt.events.TopicFetchLog.returnValues; + console.log( + "2Receipt: ", + JSON.stringify(retVals)); + assert.equal(retVals._name, "Test Topic", "Created topic name"); + }); - it('counts topics', () => { - assert - .ok(conference - .methods - .getTopicsCount() - .send({from: accounts[0], gas: 3000000}) - .on('transactionHash', function (hash) { - }) - .on('confirmation', function (confirmationNumber, receipt) { - }) - .on('receipt', function (receipt) { - const retVals = receipt.events.TopicCountLog.returnValues; - assert.equal(retVals.count, 1); - }) - .catch(e => console.log(e)) - ); + it('counts topics', async () => { + await conference + .methods + .addTopic( + "Test Topic", + "Test Topic Info") + .send({from: accounts[0], gas: 3000000}); + + const receipt = await conference + .methods + .getTopicsCount() + .send({from: accounts[0], gas: 3000000}); + const retVals = receipt.events.TopicCountLog.returnValues; + assert.equal(retVals.count, 1); }); });