github.com/decred/politeia@v1.4.0/politeiawww/cmd/pictl/testing.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 rcv1 "github.com/decred/politeia/politeiawww/api/records/v1" 13 "github.com/decred/politeia/politeiawww/cmd/shared" 14 "github.com/decred/politeia/util" 15 ) 16 17 type user struct { 18 Email string 19 Password string 20 Username string 21 } 22 23 // userNew creates a new user. 24 // 25 // This function returns with the user logged out. 26 func userNew(email, username, password string) (*user, error) { 27 // Create user 28 c := userNewCmd{ 29 Verify: true, 30 } 31 c.Args.Email = email 32 c.Args.Username = username 33 c.Args.Password = password 34 err := c.Execute(nil) 35 if err != nil { 36 return nil, fmt.Errorf("userNewCmd: %v", err) 37 } 38 39 // Log out user 40 err = userLogout() 41 if err != nil { 42 return nil, err 43 } 44 45 return &user{ 46 Email: email, 47 Username: username, 48 Password: password, 49 }, nil 50 } 51 52 // userNewRandom creates a new user with random credentials. 53 // 54 // This function returns with the user logged out. 55 func userNewRandom() (*user, error) { 56 // Hex encoding creates 2x the number of characters as bytes. 57 // Ex: 4 bytes will results in a 8 character hex string. 58 b, err := util.Random(5) 59 if err != nil { 60 return nil, err 61 } 62 var ( 63 r = hex.EncodeToString(b) 64 email = r + "@example.com" 65 username = "user_" + r 66 password = r 67 ) 68 return userNew(email, username, password) 69 } 70 71 // userLogin logs in the provided user. 72 func userLogin(u user) error { 73 c := shared.LoginCmd{} 74 c.Args.Email = u.Email 75 c.Args.Password = u.Password 76 err := c.Execute(nil) 77 if err != nil { 78 return fmt.Errorf("LoginCmd: %v", err) 79 } 80 return nil 81 } 82 83 // userLogout logs out any logged in user. 84 func userLogout() error { 85 c := shared.LogoutCmd{} 86 err := c.Execute(nil) 87 if err != nil { 88 return fmt.Errorf("LogoutCmd: %v", err) 89 } 90 return nil 91 } 92 93 // proposalOpts includes all the possible configurations which can be used 94 // when creating a new proposal using the cmdProposalNew command. 95 type proposalOpts struct { 96 Name string 97 LinkTo string 98 LinkBy string 99 Amount uint64 100 StartDate string 101 EndDate string 102 Domain string 103 104 RFP bool 105 106 Random bool 107 108 RandomImages bool 109 } 110 111 // proposalUnreviewed creates a new proposal and leaves its status as 112 // unreviewed. 113 // 114 // This function returns with the user logged out. 115 func proposalUnreviewed(u user, opts *proposalOpts) (*rcv1.Record, error) { 116 // Login user 117 err := userLogin(u) 118 if err != nil { 119 return nil, err 120 } 121 122 // Submit new proposal 123 var cn cmdProposalNew 124 if opts != nil { 125 if opts.Name != "" { 126 cn.Name = opts.Name 127 } 128 if opts.LinkTo != "" { 129 cn.LinkTo = opts.LinkTo 130 } 131 if opts.LinkBy != "" { 132 cn.LinkBy = opts.LinkBy 133 } 134 if opts.Amount != 0 { 135 cn.Amount = opts.Amount 136 } 137 if opts.StartDate != "" { 138 cn.StartDate = opts.StartDate 139 } 140 if opts.EndDate != "" { 141 cn.EndDate = opts.EndDate 142 } 143 if opts.Domain != "" { 144 cn.Domain = opts.Domain 145 } 146 if opts.RFP { 147 cn.RFP = opts.RFP 148 } 149 if opts.Random { 150 cn.Random = opts.Random 151 } 152 if opts.RandomImages { 153 cn.RandomImages = opts.RandomImages 154 } 155 } 156 r, err := proposalNew(&cn) 157 if err != nil { 158 return nil, fmt.Errorf("cmdProposalNew: %v", err) 159 } 160 161 // Edit the proposal 162 r, err = proposalEditWithOpts(r.CensorshipRecord.Token, opts) 163 if err != nil { 164 return nil, err 165 } 166 167 // Logout user 168 err = userLogout() 169 if err != nil { 170 return nil, err 171 } 172 173 return r, nil 174 } 175 176 // proposalUnvettedCensored creates a new proposal then censors the proposal. 177 // 178 // This function returns with all users logged out. 179 func proposalUnvettedCensored(author, admin user, opts *proposalOpts) (*rcv1.Record, error) { 180 // Setup an unvetted proposal 181 r, err := proposalUnreviewed(author, opts) 182 if err != nil { 183 return nil, err 184 } 185 186 // Login admin 187 err = userLogin(admin) 188 if err != nil { 189 return nil, err 190 } 191 192 // Censor the proposal 193 cs := cmdProposalSetStatus{} 194 cs.Args.Token = r.CensorshipRecord.Token 195 cs.Args.Status = strconv.Itoa(int(rcv1.RecordStatusCensored)) 196 cs.Args.Reason = "Violates proposal rules." 197 cs.Args.Version = r.Version 198 r, err = proposalSetStatus(&cs) 199 if err != nil { 200 return nil, fmt.Errorf("cmdProposalSetStatus: %v", err) 201 } 202 203 // Logout admin 204 err = userLogout() 205 if err != nil { 206 return nil, err 207 } 208 209 return r, nil 210 } 211 212 // proposalPublic creates a new proposal then makes it public. 213 // 214 // This function returns with all users logged out. 215 func proposalPublic(author, admin user, opts *proposalOpts) (*rcv1.Record, error) { 216 // Setup an unvetted proposal 217 r, err := proposalUnreviewed(author, opts) 218 if err != nil { 219 return nil, err 220 } 221 222 // Login admin 223 err = userLogin(admin) 224 if err != nil { 225 return nil, err 226 } 227 228 // Make the proposal public 229 cs := cmdProposalSetStatus{} 230 cs.Args.Token = r.CensorshipRecord.Token 231 cs.Args.Status = strconv.Itoa(int(rcv1.RecordStatusPublic)) 232 cs.Args.Version = r.Version 233 r, err = proposalSetStatus(&cs) 234 if err != nil { 235 return nil, fmt.Errorf("cmdProposalSetStatus: %v", err) 236 } 237 238 // Logout admin 239 err = userLogout() 240 if err != nil { 241 return nil, err 242 } 243 244 // Login author 245 err = userLogin(author) 246 if err != nil { 247 return nil, err 248 } 249 250 // Edit the proposal 251 r, err = proposalEditWithOpts(r.CensorshipRecord.Token, opts) 252 if err != nil { 253 return nil, err 254 } 255 256 // Logout author 257 err = userLogout() 258 if err != nil { 259 return nil, err 260 } 261 262 return r, nil 263 } 264 265 // proposalEditWithOpts edits a proposal, in addition to the proposal tokens, it 266 // accepts a pointer to a proposalOpts struct which can be used to configure 267 // the various arguments and flags of the cmdProposalEdit command. 268 func proposalEditWithOpts(token string, opts *proposalOpts) (*rcv1.Record, error) { 269 var ce cmdProposalEdit 270 if opts != nil { 271 if opts.Name != "" { 272 ce.Name = opts.Name 273 } 274 if opts.LinkTo != "" { 275 ce.LinkTo = opts.LinkTo 276 } 277 if opts.LinkBy != "" { 278 ce.LinkBy = opts.LinkBy 279 } 280 if opts.Amount != 0 { 281 ce.Amount = opts.Amount 282 } 283 if opts.StartDate != "" { 284 ce.StartDate = opts.StartDate 285 } 286 if opts.EndDate != "" { 287 ce.EndDate = opts.EndDate 288 } 289 if opts.Domain != "" { 290 ce.Domain = opts.Domain 291 } 292 if opts.RFP { 293 ce.RFP = opts.RFP 294 } 295 if opts.Random { 296 ce.Random = opts.Random 297 } 298 if opts.RandomImages { 299 ce.RandomImages = opts.RandomImages 300 } 301 } 302 ce.Args.Token = token 303 r, err := proposalEdit(&ce) 304 if err != nil { 305 return nil, fmt.Errorf("cmdProposalEdit: %v", err) 306 } 307 308 return r, nil 309 } 310 311 // proposalVettedCensored creates a new proposal, makes the proposal public, 312 // then censors the proposal. 313 // 314 // This function returns with all users logged out. 315 func proposalVettedCensored(author, admin user, opts *proposalOpts) (*rcv1.Record, error) { 316 // Create a public proposal 317 r, err := proposalPublic(author, admin, opts) 318 if err != nil { 319 return nil, err 320 } 321 322 // Login admin 323 err = userLogin(admin) 324 if err != nil { 325 return nil, err 326 } 327 328 // Censor the proposal 329 cs := cmdProposalSetStatus{} 330 cs.Args.Token = r.CensorshipRecord.Token 331 cs.Args.Status = strconv.Itoa(int(rcv1.RecordStatusCensored)) 332 cs.Args.Reason = "Violates proposal rules." 333 cs.Args.Version = r.Version 334 r, err = proposalSetStatus(&cs) 335 if err != nil { 336 return nil, fmt.Errorf("cmdProposalSetStatus: %v", err) 337 } 338 339 // Logout admin 340 err = userLogout() 341 if err != nil { 342 return nil, err 343 } 344 345 return r, nil 346 } 347 348 // proposalAbandoned creates a new proposal, makes the proposal public, 349 // then abandones the proposal. 350 // 351 // This function returns with all users logged out. 352 func proposalAbandoned(author, admin user, opts *proposalOpts) (*rcv1.Record, error) { 353 // Create a public proposal 354 r, err := proposalPublic(author, admin, opts) 355 if err != nil { 356 return nil, err 357 } 358 359 // Login admin 360 err = userLogin(admin) 361 if err != nil { 362 return nil, err 363 } 364 365 // Abandone the proposal 366 cs := cmdProposalSetStatus{} 367 cs.Args.Token = r.CensorshipRecord.Token 368 cs.Args.Status = strconv.Itoa(int(rcv1.RecordStatusArchived)) 369 cs.Args.Reason = "No activity from author in 3 weeks." 370 cs.Args.Version = r.Version 371 r, err = proposalSetStatus(&cs) 372 if err != nil { 373 return nil, fmt.Errorf("cmdProposalSetStatus: %v", err) 374 } 375 376 // Logout admin 377 err = userLogout() 378 if err != nil { 379 return nil, err 380 } 381 382 return r, nil 383 } 384 385 // voteAuthorize authorizes the ticket vote. 386 // 387 // This function returns with the user logged out. 388 func voteAuthorize(author user, token string) error { 389 // Login author 390 err := userLogin(author) 391 if err != nil { 392 return err 393 } 394 395 // Authorize the voting period 396 c := cmdVoteAuthorize{} 397 c.Args.Token = token 398 err = c.Execute(nil) 399 if err != nil { 400 return fmt.Errorf("cmdVoteAuthorize: %v", err) 401 } 402 403 // Logout author 404 err = userLogout() 405 if err != nil { 406 return err 407 } 408 409 return nil 410 } 411 412 // voteStart starts the voting period on a record. The runoff param can be 413 // used to start a runoff vote on a RFP. 414 // 415 // This function returns with the admin logged out. 416 func voteStart(admin user, token string, duration, quorum, pass uint32, runoff bool) error { 417 // Login admin 418 err := userLogin(admin) 419 if err != nil { 420 return err 421 } 422 423 // Start the voting period 424 c := cmdVoteStart{ 425 Runoff: runoff, 426 Duration: duration, 427 Quorum: &quorum, 428 Passing: pass, 429 } 430 c.Args.Token = token 431 err = c.Execute(nil) 432 if err != nil { 433 return fmt.Errorf("cmdVoteStart: %v", err) 434 } 435 436 // Logout admin 437 err = userLogout() 438 if err != nil { 439 return err 440 } 441 442 return nil 443 }