github.com/decred/politeia@v1.4.0/politeiawww/cmd/pictl/cmdproposalsetbillingstatus.go (about) 1 // Copyright (c) 2021 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 piv1 "github.com/decred/politeia/politeiawww/api/pi/v1" 13 pclient "github.com/decred/politeia/politeiawww/client" 14 "github.com/decred/politeia/politeiawww/cmd/shared" 15 ) 16 17 // cmdProposalSetBillingStatus sets the status of a proposal. 18 type cmdProposalSetBillingStatus struct { 19 Args struct { 20 Token string `positional-arg-name:"token" required:"true"` 21 Status string `positional-arg-name:"status" required:"true"` 22 Reason string `positional-arg-name:"reason"` 23 } `positional-args:"true"` 24 } 25 26 // Execute executes the cmdProposalSetBillingStatus command. 27 // 28 // This function satisfies the go-flags Commander interface. 29 func (c *cmdProposalSetBillingStatus) Execute(args []string) error { 30 // Verify user identity. This will be needed to sign the status 31 // change. 32 if cfg.Identity == nil { 33 return shared.ErrUserIdentityNotFound 34 } 35 36 // Setup client 37 opts := pclient.Opts{ 38 HTTPSCert: cfg.HTTPSCert, 39 Cookies: cfg.Cookies, 40 HeaderCSRF: cfg.CSRF, 41 Verbose: cfg.Verbose, 42 RawJSON: cfg.RawJSON, 43 } 44 pc, err := pclient.New(cfg.Host, opts) 45 if err != nil { 46 return err 47 } 48 49 // Parse billing status. This can be either the numeric status code or the 50 // human readable equivalent. 51 status, err := parseBillingStatus(c.Args.Status) 52 if err != nil { 53 return err 54 } 55 56 // Setup request 57 msg := c.Args.Token + strconv.Itoa(int(status)) + c.Args.Reason 58 sig := cfg.Identity.SignMessage([]byte(msg)) 59 sbs := piv1.SetBillingStatus{ 60 Token: c.Args.Token, 61 Status: status, 62 Reason: c.Args.Reason, 63 PublicKey: cfg.Identity.Public.String(), 64 Signature: hex.EncodeToString(sig[:]), 65 } 66 67 // Send request 68 sbsr, err := pc.PiSetBillingStatus(sbs) 69 if err != nil { 70 return err 71 } 72 73 // Print receipt 74 printf("Token : %v\n", sbs.Token) 75 printf("Status : %v\n", piv1.BillingStatuses[sbs.Status]) 76 printf("Timestamp: %v\n", dateAndTimeFromUnix(sbsr.Timestamp)) 77 printf("Receipt : %v\n", sbsr.Receipt) 78 return nil 79 } 80 81 func parseBillingStatus(status string) (piv1.BillingStatusT, error) { 82 // Parse billing status. This can be either the numeric status code or the 83 // human readable equivalent. 84 var ( 85 bs piv1.BillingStatusT 86 87 statuses = map[string]piv1.BillingStatusT{ 88 "active": piv1.BillingStatusActive, 89 "close": piv1.BillingStatusClosed, 90 "closed": piv1.BillingStatusClosed, 91 "complete": piv1.BillingStatusCompleted, 92 "completed": piv1.BillingStatusCompleted, 93 } 94 ) 95 u, err := strconv.ParseUint(status, 10, 32) 96 if err == nil { 97 // Numeric status code found 98 bs = piv1.BillingStatusT(u) 99 } else if s, ok := statuses[status]; ok { 100 // Human readable status code found 101 bs = s 102 } else { 103 return bs, fmt.Errorf("invalid status '%v'", status) 104 } 105 106 return bs, nil 107 } 108 109 // proposalSetBillingStatusHelpMsg is printed to stdout by the help command. 110 const proposalSetBillingStatusHelpMsg = `proposalsetbillingstatus "token" "status" "reason" 111 112 Set the billing status of a proposal. 113 114 Valid statuses: 115 (1) active 116 (2) close 117 (3) complete 118 119 The following statuses require a billing status change reason to be included: 120 close 121 122 Arguments: 123 1. token (string, required) Proposal censorship token 124 2. status (string, required) New billing status 125 3. reason (string, optional) Billing status change reason 126 `