1
0

cli.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package main
  2. import (
  3. "bufio"
  4. "flag"
  5. "fmt"
  6. "io"
  7. "os"
  8. "strings"
  9. paneldb "git.lattuga.net/boyska/feedpanel/db"
  10. "github.com/go-pg/pg"
  11. "github.com/howeyc/gopass"
  12. )
  13. type commandFunc func([]string) error
  14. var globalOptions struct {
  15. verbose bool
  16. pgOptions pg.Options
  17. }
  18. var cmdMap map[string]commandFunc
  19. func init() {
  20. cmdMap = map[string]commandFunc{
  21. "batch": cmdBatch,
  22. "setup": cmdSetup,
  23. "adduser": cmdAddUser,
  24. "listusers": cmdListUsers,
  25. "showuser": cmdShowUser,
  26. }
  27. }
  28. func getDB() paneldb.DB {
  29. pgdb := pg.Connect(&globalOptions.pgOptions)
  30. db := paneldb.DB{PgDB: pgdb}
  31. return db
  32. }
  33. func cmdSetup(args []string) error {
  34. db := getDB()
  35. err := db.Setup()
  36. if err != nil {
  37. fmt.Fprintln(os.Stderr, err)
  38. os.Exit(1)
  39. }
  40. if globalOptions.verbose {
  41. fmt.Println("Tables created")
  42. }
  43. os.Exit(0)
  44. return nil
  45. }
  46. func askPassword() (string, error) {
  47. fmt.Print("New password: ")
  48. pass, err := gopass.GetPasswd()
  49. if err != nil {
  50. return "", err
  51. }
  52. fmt.Print("Retype new password: ")
  53. pass2, err := gopass.GetPasswd()
  54. if err != nil {
  55. return "", err
  56. }
  57. if string(pass) != string(pass2) {
  58. return "", fmt.Errorf("Passwords differ")
  59. }
  60. return string(pass), nil
  61. }
  62. func cmdAddUser(args []string) error {
  63. flagset := flag.NewFlagSet(args[0], flag.ExitOnError)
  64. password := flagset.String("password", "", "set password from command line; INSECURE!")
  65. flagset.Parse(args[1:])
  66. if len(flagset.Args()) < 2 {
  67. fmt.Fprintf(os.Stderr, "Usage: %s [options] USER EMAIL\n", args[0])
  68. flagset.PrintDefaults()
  69. os.Exit(2)
  70. }
  71. user := flagset.Args()[0]
  72. email := flagset.Args()[1]
  73. if *password == "" {
  74. pass, err := askPassword()
  75. if err != nil {
  76. fmt.Fprintln(os.Stderr, "Error:", err)
  77. os.Exit(1)
  78. }
  79. *password = string(pass)
  80. }
  81. db := getDB()
  82. err := db.UserAdd(user, email, *password)
  83. if err != nil {
  84. fmt.Fprintln(os.Stderr, err)
  85. os.Exit(1)
  86. }
  87. if globalOptions.verbose {
  88. fmt.Printf("Success: user %s added\n", user)
  89. }
  90. os.Exit(0)
  91. return nil
  92. }
  93. func composeListUserOutput(user paneldb.User, usernameFlag, emailFlag, dateCreatedFlag bool) {
  94. var row string
  95. if usernameFlag {
  96. row += user.Name
  97. if emailFlag || dateCreatedFlag {
  98. row += "\t"
  99. }
  100. }
  101. if emailFlag {
  102. row += user.Email
  103. if dateCreatedFlag {
  104. row += "\t"
  105. }
  106. }
  107. if dateCreatedFlag {
  108. row += user.DateCreated
  109. }
  110. fmt.Fprintln(os.Stdout, row)
  111. }
  112. func cmdListUsers(args []string) error {
  113. flagset := flag.NewFlagSet(args[0], flag.ExitOnError)
  114. usernameFlag := flagset.Bool("no-nick", true, "skip printing usernames")
  115. emailFlag := flagset.Bool("no-email", true, "skip printing emails")
  116. dateCreatedFlag := flagset.Bool("created", false, "print date of user creation")
  117. headerFlag := flagset.Bool("no-header", false, "skip printing the header")
  118. flagset.Parse(args[1:])
  119. db := getDB()
  120. users, err := db.GetUsers()
  121. if err != nil {
  122. fmt.Fprintln(os.Stderr, "Error:", err)
  123. os.Exit(1)
  124. }
  125. // Printing the header
  126. if !*headerFlag {
  127. header := paneldb.User{
  128. Name: "username",
  129. Email: "email",
  130. DateCreated: "date_created",
  131. }
  132. separator := paneldb.User{
  133. Name: "--------",
  134. Email: "-----",
  135. DateCreated: "------------",
  136. }
  137. composeListUserOutput(header, *usernameFlag, *emailFlag, *dateCreatedFlag)
  138. composeListUserOutput(separator, *usernameFlag, *emailFlag, *dateCreatedFlag)
  139. }
  140. // Printing the user list
  141. for _, user := range users {
  142. composeListUserOutput(user, *usernameFlag, *emailFlag, *dateCreatedFlag)
  143. }
  144. return nil
  145. }
  146. func cmdShowUser(args []string) error {
  147. flagset := flag.NewFlagSet(args[0], flag.ExitOnError)
  148. byEmail := flagset.String("email", "", "Search by email")
  149. byName := flagset.String("username", "", "Search by username")
  150. flagset.Parse(args[1:])
  151. if *byEmail != "" && *byName != "" {
  152. fmt.Fprintln(os.Stderr, "-email and -username conflict")
  153. os.Exit(2)
  154. }
  155. if *byEmail == "" && *byName == "" {
  156. fmt.Fprintln(os.Stderr, "at least one of -email and -username must be specified")
  157. os.Exit(2)
  158. }
  159. db := getDB()
  160. var user paneldb.User
  161. var err error
  162. switch {
  163. case *byName != "":
  164. user, err = db.GetUserByName(*byName)
  165. case *byEmail != "":
  166. user, err = db.GetUserByEmail(*byEmail)
  167. }
  168. if err != nil {
  169. return err
  170. }
  171. fmt.Println(user)
  172. return nil
  173. }
  174. func usage(w io.Writer) {
  175. fmt.Fprintf(w, "Usage: %s SUBCOMMAND [command args...]\n", os.Args[0])
  176. fmt.Fprintln(w, "\nSubcommands:")
  177. for cmdName := range cmdMap {
  178. fmt.Fprintln(w, " -", cmdName)
  179. }
  180. }
  181. func runLine(args []string) {
  182. cmdName := args[0]
  183. cmdFunc, ok := cmdMap[cmdName]
  184. if !ok {
  185. fmt.Fprintf(os.Stderr, "Invalid command `%s`\n", cmdName)
  186. usage(os.Stderr)
  187. os.Exit(2)
  188. }
  189. err := cmdFunc(args)
  190. if err != nil {
  191. fmt.Fprintln(os.Stderr, "Error")
  192. fmt.Fprintln(os.Stderr, err)
  193. os.Exit(1)
  194. }
  195. }
  196. func cmdBatch(args []string) error {
  197. scanner := bufio.NewScanner(os.Stdin)
  198. for scanner.Scan() {
  199. line := scanner.Text()
  200. runLine(strings.Split(line, " "))
  201. }
  202. if scanner.Err() != nil {
  203. fmt.Fprintln(os.Stderr, "Error reading stdin:", scanner.Err())
  204. os.Exit(1)
  205. }
  206. os.Exit(0)
  207. return nil
  208. }
  209. func main() {
  210. flag.StringVar(&globalOptions.pgOptions.User, "db-user", "panel", "The user to connect to database to")
  211. flag.StringVar(&globalOptions.pgOptions.Password, "db-pass", "", "database password")
  212. flag.StringVar(&globalOptions.pgOptions.Database, "db-name", "feeds", "database name")
  213. flag.StringVar(&globalOptions.pgOptions.Addr, "db-addr", "127.0.0.1:5432", "database network address")
  214. flag.BoolVar(&globalOptions.verbose, "verbose", false, "verbose output")
  215. flag.Parse()
  216. if len(flag.Args()) < 1 {
  217. fmt.Fprintln(os.Stderr, "Not enough arguments!")
  218. usage(os.Stderr)
  219. os.Exit(2)
  220. }
  221. runLine(flag.Args())
  222. os.Exit(0)
  223. }