Skip to content

Commit 900180c

Browse files
committed
CAS-647: Add Quorum Voting
1 parent 4d3029b commit 900180c

14 files changed

Lines changed: 166 additions & 48 deletions

File tree

backend/main/models/proposal.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type Proposal struct {
4242
Voucher *shared.Voucher `json:"voucher,omitempty"`
4343
Achievements_done bool `json:"achievementsDone"`
4444
TallyMethod string `json:"voteType" validate:"required"`
45+
Quorum *float64 `json:"quorum,omitempty"`
4546
}
4647

4748
type UpdateProposalRequestPayload struct {
@@ -146,9 +147,10 @@ func (p *Proposal) CreateProposal(db *s.Database) error {
146147
cid,
147148
composite_signatures,
148149
voucher,
149-
tally_method
150+
tally_method,
151+
quorum
150152
)
151-
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
153+
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
152154
RETURNING id, created_at
153155
`,
154156
p.Community_id,
@@ -167,6 +169,7 @@ func (p *Proposal) CreateProposal(db *s.Database) error {
167169
p.Composite_signatures,
168170
p.Voucher,
169171
p.TallyMethod,
172+
p.Quorum,
170173
).Scan(&p.ID, &p.Created_at)
171174

172175
return err
@@ -210,17 +213,19 @@ func (p *Proposal) UpdateDraftProposal(db *s.Database) error {
210213
strategy = COALESCE($3, strategy),
211214
min_balance = COALESCE($4, min_balance),
212215
max_weight = COALESCE($5, max_weight),
213-
start_time = COALESCE($6, start_time),
214-
end_time = COALESCE($7, end_time),
215-
body = COALESCE($8, body),
216-
block_height = COALESCE($9, block_height),
217-
cid = COALESCE($10, cid)
218-
WHERE id = $11
216+
quorum = COALESCE($6, quorum),
217+
start_time = COALESCE($7, start_time),
218+
end_time = COALESCE($8, end_time),
219+
body = COALESCE($9, body),
220+
block_height = COALESCE($10, block_height),
221+
cid = COALESCE($11, cid)
222+
WHERE id = $12
219223
`, p.Name,
220224
p.Choices,
221225
p.Strategy,
222226
p.Min_balance,
223227
p.Max_weight,
228+
p.Quorum,
224229
p.Start_time,
225230
p.End_time,
226231
p.Body,

backend/main/server/controllers.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,6 @@ func (a *App) createProposal(w http.ResponseWriter, r *http.Request) {
398398
var p models.Proposal
399399
p.Community_id = communityId
400400

401-
402401
if err := validatePayload(r.Body, &p); err != nil {
403402
log.Error().Err(err).Msg("Error validating payload")
404403
respondWithError(w, errIncompleteRequest)

backend/main/server/helpers.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ func (h *Helpers) createProposal(p models.Proposal) (models.Proposal, errorRespo
606606

607607
canUserCreateProposal := community.CanUserCreateProposal(h.A.DB, h.A.FlowAdapter, p.Creator_addr)
608608

609-
if err := handlePermissionErrorr(canUserCreateProposal); err != nilErr {
609+
if err := handlePermissionError(canUserCreateProposal); err != nilErr {
610610
return models.Proposal{}, err
611611
}
612612

@@ -652,7 +652,7 @@ func (h *Helpers) createDraftProposal(c models.Community, p models.Proposal) (mo
652652
p.Creator_addr,
653653
)
654654

655-
if err := handlePermissionErrorr(canUserCreateProposal); err != nilErr {
655+
if err := handlePermissionError(canUserCreateProposal); err != nilErr {
656656
return models.Proposal{}, err
657657
}
658658

@@ -729,7 +729,7 @@ func (h *Helpers) updateDraftProposal(p models.Proposal) (models.Proposal, error
729729
p.Creator_addr,
730730
)
731731

732-
if err := handlePermissionErrorr(canUserCreateProposal); err != nilErr {
732+
if err := handlePermissionError(canUserCreateProposal); err != nilErr {
733733
return models.Proposal{}, err
734734
}
735735

@@ -742,7 +742,7 @@ func (h *Helpers) updateDraftProposal(p models.Proposal) (models.Proposal, error
742742
return p, nilErr
743743
}
744744

745-
func handlePermissionErrorr(result models.CanUserCreateProposalResponse) errorResponse {
745+
func handlePermissionError(result models.CanUserCreateProposalResponse) errorResponse {
746746
// If user doesn't have permission, populate errorResponse
747747
// with reason and error.
748748
if !result.HasPermission {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE proposals DROP COLUMN IF EXISTS quorum;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE proposals ADD COLUMN quorum float;

frontend/packages/client/src/api/proposals.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ export const createProposalApiReq = async ({
4848
timestamp,
4949
} = {}) => {
5050
const { communityId, ...proposalData } = proposalPayload;
51+
console.log(proposalData);
52+
53+
if (proposalData.voteType === 'basic') {
54+
proposalData.choices = [
55+
{ choiceText: 'For', choiceImgUrl: null },
56+
{ choiceText: 'Against', choiceImgUrl: null },
57+
{ choiceText: 'Abstain', choiceImgUrl: null },
58+
];
59+
}
60+
5161
const url = `${COMMUNITIES_URL}/${communityId}/proposals`;
5262
const fetchOptions = {
5363
method: 'POST',

frontend/packages/client/src/components/Proposal/VoteHeader.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Wrapper = ({ children }) => (
99
</h3>
1010
);
1111

12-
export default function VoteHeader({ status }) {
12+
export default function VoteHeader({ status, voteType = 'single-choice' }) {
1313
// Status: user-voted, invite-to-vote, is-closed
1414
const message = {
1515
'user-voted': (
@@ -20,7 +20,12 @@ export default function VoteHeader({ status }) {
2020
You successfully voted on this proposal!
2121
</div>
2222
),
23-
'invite-to-vote': <>Rank your vote &#10024;</>,
23+
'invite-to-vote': (
24+
<>
25+
{voteType === 'single-choice' ? 'Cast your vote' : 'Rank your vote'}{' '}
26+
&#10024;
27+
</>
28+
),
2429
'is-closed': <>Voting has ended on this proposal.</>,
2530
};
2631

frontend/packages/client/src/components/ProposalCreate/FormConfig.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,21 @@ const StepTwoSchema = yup.object().shape({
4646
})
4747
),
4848
})
49-
.when('voteType', (voteType, schema) =>
50-
voteType === 'single-choice'
49+
.when('voteType', (voteType, schema) => {
50+
if (voteType === 'basic') return;
51+
return voteType === 'single-choice'
5152
? schema.min(2, 'Please add a choice, minimum amount is two')
52-
: schema.min(3, 'Please add a choice, minimum amount is three')
53-
)
53+
: schema.min(3, 'Please add a choice, minimum amount is three');
54+
})
5455
.unique('value', 'Invalid duplicated option'),
56+
quorum: yup
57+
.string()
58+
.trim()
59+
.matches(/\s+$|^$|(^[0-9]+$)/, 'Quorum threshold must be a valid number')
60+
.when('voteType', (voteType, schema) => {
61+
if (voteType !== 'basic') return;
62+
return schema.required('Quorum threshold is required');
63+
}),
5564
maxWeight: yup
5665
.string()
5766
.trim()
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export default function BasicVoteExample() {
2+
return (
3+
<>
4+
{['For', 'Against', 'Abstain'].map((text, index) => (
5+
<div
6+
className="is-flex is-align-items-center is-justify-content-left mb-1"
7+
style={{ whiteSpace: 'nowrap', width: 75 }}
8+
key={index}
9+
>
10+
<div
11+
className="rounded-full has-background-grey has-text-white mr-2 is-flex is-align-items-center is-justify-content-center"
12+
style={{ width: 12, height: 12 }}
13+
>
14+
{index === 0 ? (
15+
<span style={{ fontSize: 7, paddingTop: 1 }}>&#x2713;</span>
16+
) : null}
17+
</div>
18+
<span className="smaller-text">{text}</span>
19+
</div>
20+
))}
21+
</>
22+
);
23+
}

frontend/packages/client/src/components/ProposalCreate/StepTwo/ChoiceOptionCreator.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default function ChoiceOptionCreator({
2020
setValue('tabOption', option);
2121
};
2222

23-
if (voteType === 'ranked-choice') {
23+
if (voteType === 'ranked-choice' || voteType === 'basic') {
2424
setTab('text-based');
2525
}
2626

0 commit comments

Comments
 (0)