Open cdparra opened 5 years ago
[ ] POST ballot is returning always {"error":"Votes limit can't be blank"}
even when in all cases, default values for ballot configurations are included in the body. The results should be that a ballot is created. After a ballot is created, the WG should be updated to include the ballot uuid in the property consensus_ballot
. If there was another ballot in there, it should be archived in the working_group_ballot_history
table.
[ ] Configure voting modal has missing fields:
Ballot configurations
. Each configuration is later included as a config object, with a property key and property value, inside an array of configurations called ballot_configurations
. Below the list of configs that should be shown and are currently not:
4.1. Range => should display fields to configure a minimum and maximum score that can be assigned to candidates with labels Minimum score
, and Maximum score
. Below an example that shows the keys to use.{
"ballot": {...},
"ballot_configurations":[
{"key":"component.voting.system.range.min-score","value":0},
{"key":"component.voting.system.range.max-score","value":100}]
"ballot_registration_fields": {...}
}
4.2. Ranked => should display a field asking what is the number of proposals to rank with the label `How many proposals can be included in the ranking?`
{
"ballot": {...}.
"ballot_configurations": [
{"key":"component.voting.system.ranked.number-proposals","value":5}
],
"ballot_registration_fields": {...}
}
4.3. Distribution => should display a field asking to configure the `Number of votes or points that the voter can distribute among candidates`. See the example below of how this is included in the body.
{
"ballot": {...}.
"ballot_configurations": [
{"key": "component.voting.system.distributed.points", "value": 30}
],
"ballot_registration_fields": {...}
}
4.4. Plurality => should ask `Which type of plurality voting will be used?` with options being: "YES votes only", "YES and NO votes", "YES, NO and ABSTAIN votes", and "YES, NO, ABSTAIN and BLOCK votes". If the later is chosen, another option should appear asking `What's the blocking threshold`?
{
"ballot": {...}.
"ballot_configurations": [
{"key": "component.voting.system.plurality.type", "value": "YES"}
],
"ballot_registration_fields": {...}
}
Currently, the Voting API has support for tallying votes of a ballot of types plurality, range, and distributed (named cumulative in the API). See code below to know which module implements each type.
...
when "PLURALITY", "APPROVAL"
RangeVoting.sort_candidates_by_score(@ballot.votes) results = PluralityVoting.sort_candidates_by_score(@ballot.votes)
when "RANGE"
results = PluralityVoting.sort_candidates_by_score(@ballot.votes)
when "DISTRIBUTED", "CUMULATIVE"
results = CumulativeVoting.sort_candidates_by_score(@ballot.votes)
end
None of these voting systems are fully complete. Basically, we only have the methods for tallying the votes for each system. For example, in distributed, the tallying process simply sums up votes received for each candidate and returns the sorted array of candidates along with their scores, but the validation mechanism is not implemented for any voting system (i.e., we do not check if the voter submitted only N votes in distributed for example). When voting is distributed, each voter has N votes to distribute among the candidates. The winning proposal is the one with most votes. Or using the Schulze
method.
Validation is needed in all the systems when saving or updating votes (see https://github.com/socialappslab/appcivist-voting-api/blob/d83e844979531a9aa5baffd36325912ec93490ae/app/models/ballot_paper.rb), the voting API does not check if the votes distributed by the voter equal the total number of votes that are allowed to distribute (in the ballot configurations) in the case of distributed. It does not check if votes are within the minimum and maximum allowed scores in RANGE, and it does not check plurality rules related to abstain or blocking options. So this is a TODO in the voting API, that could be simply implemented in the UI for the moment. In fact, the UI might already have some of these checks in place for the campaign page, but certainly not for the WG page.
So, we should now focus only in the WG voting story, and fix later the current issues with campaign voting.
The basic idea for voting in the WG page is that a coordinator can, at any given time, create a ballot that would include a list of candidates representing proposals in the group. By default, all published proposals could be included, but ideally, the coordinator should be able to select which proposals to include in the ballot (so as to create mini decision making competitions sort of).
The current model only allows for one ballot at a time, but ideally, a WG might contain several ballots at the same time (for example, to make decisions on multiple groups of dissensus proposals), and members could select which ballot they want to vote on, therefore filtering contributions bellow including only those in the selected ballot.
The idea of having multiple ballots (i.e., multiple voting processes with different list of candidates) running in parallel might also be useful for the campaign page. Perhaps also there the voting can be configured by coordinators rather than automatically (as it is now).
Based on comments above, below is the preliminary ToDo of priorities (on top of all the problems identified in the previous comments).
This is still an issue
Campaign Voting Status:
ballotIndex
which is an index of all ballots associated to this campaign or assembly, indexed by uuid. The propertycurrentBallot
of the campaign should indicate which of these ballots is the current one.Problems:
Related errors on campaign loading
$scope.afterLoadingBallotSuccess = function(data) { this.ballotPaperNotFound = !1, this.startVotingDisabled = !1, this.showVotingButtons = !0, this.ballotPaper = data, this.ballotPaper && (this.ballot = this.ballotPaper.ballot, this.ballotPassword = this.ballot.password, this.voteRecord = this.ballotPaper.vote, this.ballotPaperFinished = 0 < this.voteRecord.status, this.votingSignature = this.voteRecord.signature, this.voteRecord || (this.voteRecord = this.ballotPaper.vote = []), this.votes = this.voteRecord ? this.voteRecord.votes : [], this.votes && 0 !== this.votes.length ? this.votesIndex = this.voteRecord.votesIndex : this.votesIndex = this.voteRecord.votesIndex = {}, this.initializeBallotTokens()), this.savingVotes && (this.savingVotes = !1, angular.element("#saveVotes").modal({ show: !0 })), this.finalizingVotes && (this.finalizingVotes = !1, angular.element("#finalizeVotes").modal({ show: !1 }), angular.element("#finalizeVotesDone").modal({ show: !0 })) }
this.updateVote = function() { null !== this.voteValue && void 0 !== this.voteValue && "null" !== this.voteValue && "undefined" !== this.voteValue || (this.voteValue = 0); var oldValue = this.vote.value; null != oldValue && "null" !== oldValue && "undefined" !== oldValue || (oldValue = 0); var diff = this.voteValue - oldValue , updatedRemainder = this.ballotTokens ? this.ballotTokens.points - diff : 0; 0 < diff && 0 <= updatedRemainder || diff < 0 && updatedRemainder <= this.maxTokens ? (this.vote.value = this.voteValue + "", this.ballotTokens.points = updatedRemainder) : this.voteValue = parseInt(this.vote.value) }
PUT https://testplatform.appcivist.org/voting/api/v0/ballot/9e27205c-3a65-4fe2-b7a4-2a7d932839af/vote 404 (Not Found)
ui.js:3 TypeError: Cannot convert undefined or null to object at Scope. (https://testpb.appcivist.org/scripts/app.js:3:276433)
at fn (eval at compile (https://testpb.appcivist.org/scripts/ui.js:1:1), :4:230)
at expensiveCheckFn (https://testpb.appcivist.org/scripts/ui.js:3:921649)
at callback (https://testpb.appcivist.org/scripts/ui.js:3:992237)
at Scope.$eval (https://testpb.appcivist.org/scripts/ui.js:3:938790)
at Scope.$apply (https://testpb.appcivist.org/scripts/ui.js:3:939129)
at HTMLButtonElement. (https://testpb.appcivist.org/scripts/ui.js:3:992344)
at HTMLButtonElement.dispatch (https://testpb.appcivist.org/scripts/ui.js:3:661083)
at HTMLButtonElement.r.handle (https://testpb.appcivist.org/scripts/ui.js:3:659169)
at HTMLButtonElement.wrapped (https://testpb.appcivist.org/scripts/ui.js:3:2371707) undefined