github.com/decred/politeia@v1.4.0/politeiawww/cmd/pictl/cmdcommentvote.go (about)

     1  // Copyright (c) 2020-2020 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"encoding/hex"
     9  	"fmt"
    10  	"strconv"
    11  
    12  	"github.com/decred/politeia/politeiad/api/v1/identity"
    13  	cmv1 "github.com/decred/politeia/politeiawww/api/comments/v1"
    14  	pclient "github.com/decred/politeia/politeiawww/client"
    15  	"github.com/decred/politeia/politeiawww/cmd/shared"
    16  	"github.com/decred/politeia/util"
    17  )
    18  
    19  // cmdCommentVote is used to upvote/downvote a proposal comment using the
    20  // logged in the user.
    21  type cmdCommentVote struct {
    22  	Args struct {
    23  		Token     string `positional-arg-name:"token"`
    24  		CommentID uint32 `positional-arg-name:"commentID"`
    25  		Vote      string `positional-arg-name:"vote"`
    26  	} `positional-args:"true" required:"true"`
    27  }
    28  
    29  // Execute executes the cmdCommentVote command.
    30  //
    31  // This function satisfies the go-flags Commander interface.
    32  func (c *cmdCommentVote) Execute(args []string) error {
    33  	// Check for user identity. A user identity is required to sign
    34  	// the comment vote.
    35  	if cfg.Identity == nil {
    36  		return shared.ErrUserIdentityNotFound
    37  	}
    38  
    39  	// Setup client
    40  	opts := pclient.Opts{
    41  		HTTPSCert:  cfg.HTTPSCert,
    42  		Cookies:    cfg.Cookies,
    43  		HeaderCSRF: cfg.CSRF,
    44  		Verbose:    cfg.Verbose,
    45  		RawJSON:    cfg.RawJSON,
    46  	}
    47  	pc, err := pclient.New(cfg.Host, opts)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	// Parse vote preference
    53  	votes := map[string]cmv1.VoteT{
    54  		"upvote":   cmv1.VoteUpvote,
    55  		"downvote": cmv1.VoteDownvote,
    56  		"1":        cmv1.VoteUpvote,
    57  		"-1":       cmv1.VoteDownvote,
    58  	}
    59  	vote, ok := votes[c.Args.Vote]
    60  	if !ok {
    61  		return fmt.Errorf("invalid vote option '%v' \n%v",
    62  			c.Args.Vote, commentVoteHelpMsg)
    63  	}
    64  
    65  	// Setup request
    66  	state := cmv1.RecordStateVetted
    67  	msg := strconv.FormatUint(uint64(state), 10) + c.Args.Token +
    68  		strconv.FormatUint(uint64(c.Args.CommentID), 10) +
    69  		strconv.FormatInt(int64(vote), 10)
    70  	sig := cfg.Identity.SignMessage([]byte(msg))
    71  	v := cmv1.Vote{
    72  		State:     state,
    73  		Token:     c.Args.Token,
    74  		CommentID: c.Args.CommentID,
    75  		Vote:      vote,
    76  		Signature: hex.EncodeToString(sig[:]),
    77  		PublicKey: cfg.Identity.Public.String(),
    78  	}
    79  
    80  	// Send request
    81  	cvr, err := pc.CommentVote(v)
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	// Verify receipt
    87  	vr, err := client.Version()
    88  	if err != nil {
    89  		return err
    90  	}
    91  	serverID, err := identity.PublicIdentityFromString(vr.PubKey)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	receiptb, err := util.ConvertSignature(cvr.Receipt)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	if !serverID.VerifyMessage([]byte(v.Signature), receiptb) {
   100  		return fmt.Errorf("could not verify receipt")
   101  	}
   102  
   103  	// Print receipt
   104  	printf("Downvotes: %v\n", int64(cvr.Downvotes)*-1)
   105  	printf("Upvotes  : %v\n", cvr.Upvotes)
   106  	printf("Timestamp: %v\n", dateAndTimeFromUnix(cvr.Timestamp))
   107  	printf("Receipt  : %v\n", cvr.Receipt)
   108  
   109  	return nil
   110  }
   111  
   112  // commentVoteHelpMsg is printed to stdout by the help command.
   113  const commentVoteHelpMsg = `commentvote "token" "commentID" "vote"
   114  
   115  Upvote or downvote a comment.
   116  
   117  Requires the user to be logged in. Votes can only be cast on vetted records.
   118  
   119  Arguments:
   120  1. token      (string, required)  Proposal censorship token
   121  2. commentID  (string, required)  Comment ID
   122  3. vote       (string, required)  Upvote or downvote
   123  
   124  You can specify either the numeric vote option (1 or -1) or the human readable
   125  vote option.
   126  upvote (1)
   127  downvote (-1)
   128  
   129  Example usage
   130  $ commentvote d594fbadef0f9378 3 downvote
   131  $ commentvote d594fbadef0f9378 3 -1
   132  `