github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/cmd/snap/cmd_buy.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package main 21 22 import ( 23 "fmt" 24 "strings" 25 26 "github.com/snapcore/snapd/client" 27 "github.com/snapcore/snapd/i18n" 28 29 "github.com/jessevdk/go-flags" 30 ) 31 32 var shortBuyHelp = i18n.G("Buy a snap") 33 var longBuyHelp = i18n.G(` 34 The buy command buys a snap from the store. 35 `) 36 37 type cmdBuy struct { 38 clientMixin 39 Positional struct { 40 SnapName remoteSnapName 41 } `positional-args:"yes" required:"yes"` 42 } 43 44 func init() { 45 cmd := addCommand("buy", shortBuyHelp, longBuyHelp, func() flags.Commander { 46 return &cmdBuy{} 47 }, map[string]string{}, []argDesc{{ 48 name: "<snap>", 49 // TRANSLATORS: This should not start with a lowercase letter. 50 desc: i18n.G("Snap name"), 51 }}) 52 cmd.hidden = true 53 } 54 55 func (x *cmdBuy) Execute(args []string) error { 56 if len(args) > 0 { 57 return ErrExtraArgs 58 } 59 60 return buySnap(x.client, string(x.Positional.SnapName)) 61 } 62 63 func buySnap(cli *client.Client, snapName string) error { 64 user := cli.LoggedInUser() 65 if user == nil { 66 return fmt.Errorf(i18n.G("You need to be logged in to purchase software. Please run 'snap login' and try again.")) 67 } 68 69 if strings.ContainsAny(snapName, ":*") { 70 return fmt.Errorf(i18n.G("cannot buy snap: invalid characters in name")) 71 } 72 73 snap, resultInfo, err := cli.FindOne(snapName) 74 if err != nil { 75 return err 76 } 77 78 opts := &client.BuyOptions{ 79 SnapID: snap.ID, 80 Currency: resultInfo.SuggestedCurrency, 81 } 82 83 opts.Price, opts.Currency, err = getPrice(snap.Prices, opts.Currency) 84 if err != nil { 85 return fmt.Errorf(i18n.G("cannot buy snap: %v"), err) 86 } 87 88 if snap.Status == "available" { 89 return fmt.Errorf(i18n.G("cannot buy snap: it has already been bought")) 90 } 91 92 err = cli.ReadyToBuy() 93 if err != nil { 94 if e, ok := err.(*client.Error); ok { 95 switch e.Kind { 96 case client.ErrorKindNoPaymentMethods: 97 return fmt.Errorf(i18n.G(`You need to have a payment method associated with your account in order to buy a snap, please visit https://my.ubuntu.com/payment/edit to add one. 98 99 Once you’ve added your payment details, you just need to run 'snap buy %s' again.`), snap.Name) 100 case client.ErrorKindTermsNotAccepted: 101 return fmt.Errorf(i18n.G(`In order to buy %q, you need to agree to the latest terms and conditions. Please visit https://my.ubuntu.com/payment/edit to do this. 102 103 Once completed, return here and run 'snap buy %s' again.`), snap.Name, snap.Name) 104 } 105 } 106 return err 107 } 108 109 // TRANSLATORS: %q, %q and %s are the snap name, developer, and price. Please wrap the translation at 80 characters. 110 fmt.Fprintf(Stdout, i18n.G(`Please re-enter your Ubuntu One password to purchase %q from %q 111 for %s. Press ctrl-c to cancel.`), snap.Name, snap.Publisher.Username, formatPrice(opts.Price, opts.Currency)) 112 fmt.Fprint(Stdout, "\n") 113 114 err = requestLogin(cli, user.Email) 115 if err != nil { 116 return err 117 } 118 119 _, err = cli.Buy(opts) 120 if err != nil { 121 if e, ok := err.(*client.Error); ok { 122 switch e.Kind { 123 case client.ErrorKindPaymentDeclined: 124 return fmt.Errorf(i18n.G(`Sorry, your payment method has been declined by the issuer. Please review your 125 payment details at https://my.ubuntu.com/payment/edit and try again.`)) 126 } 127 } 128 return err 129 } 130 131 // TRANSLATORS: %q and %s are the same snap name. Please wrap the translation at 80 characters. 132 fmt.Fprintf(Stdout, i18n.G(`Thanks for purchasing %q. You may now install it on any of your devices 133 with 'snap install %s'.`), snapName, snapName) 134 fmt.Fprint(Stdout, "\n") 135 136 return nil 137 }