admin.go (view raw)
1package main
2
3// Commands for administering your instance
4// reset user password -> generate link
5// delete user
6
7// Run some scripts to setup your instance
8
9import (
10 "flag"
11 "fmt"
12 "io/ioutil"
13 "log"
14 "os"
15 "path"
16 "path/filepath"
17)
18
19// TODO improve cli
20func runAdminCommand() {
21 args := flag.Args() // again?
22 if len(args) < 3 {
23 fmt.Println("Expected subcommand with parameter activate-user|delete-user|make-admin|rename-user")
24 os.Exit(1)
25 }
26 var err error
27 switch args[1] {
28 case "activate-user":
29 username := args[2]
30 err = activateUser(username)
31 case "delete-user":
32 username := args[2]
33 // TODO add confirmation
34 err = deleteUser(username)
35 case "make-admin":
36 username := args[2]
37 err = makeAdmin(username)
38 case "rename-user":
39 username := args[2]
40 newUsername := args[3]
41 err = renameUser(username, newUsername)
42 // case "set-password":
43 }
44 if err != nil {
45 log.Fatal(err)
46 }
47 // reset password
48
49}
50
51func makeAdmin(username string) error {
52 _, err := DB.Exec("UPDATE user SET admin = true WHERE username = $1", username)
53 if err != nil {
54 return err
55 }
56 log.Println("Made admin user", username)
57 return nil
58}
59
60func setPassword(username string, newPass string) error {
61 return nil
62}
63
64func activateUser(username string) error {
65 _, err := DB.Exec("UPDATE user SET active = true WHERE username = ?", username)
66 if err != nil {
67 // TODO verify 1 row updated
68 return err
69 }
70 log.Println("Activated user", username)
71 baseIndex := `# Welcome to Flounder!
72## About
73Welcome to an ultra-lightweight platform for making and sharing small websites. You can get started by editing this page -- remove this content and replace it with whatever you like! It will be live at <your-name>.flounder.online. You can go there right now to see what this page currently looks like. Here is a link to a page which will give you more information about using flounder:
74=> //admin.flounder.online
75
76And here's a guide to the text format that Flounder uses to create pages, Gemini. These pages are converted into HTML so they can be displayed in a web browser.
77=> //admin.flounder.online/gemini_text_guide.gmi
78
79Have fun!`
80 // Redundant filepath.Clean call just in case.
81 username = filepath.Clean(username)
82 os.Mkdir(path.Join(c.FilesDirectory, username), os.ModePerm)
83 ioutil.WriteFile(path.Join(c.FilesDirectory, username, "index.gmi"), []byte(baseIndex), 0644)
84 os.Mkdir(path.Join(c.FilesDirectory, username), os.ModePerm)
85 return nil
86}
87
88func renameUser(oldUsername string, newUsername string) error {
89 err := isOkUsername(newUsername)
90 if err != nil {
91 return err
92 }
93 res, err := DB.Exec("UPDATE user set username = ? WHERE username = ?", newUsername, oldUsername)
94 if err != nil {
95 return err
96 }
97 rowsAffected, err := res.RowsAffected()
98 if rowsAffected != 1 {
99 return fmt.Errorf("No User updated %s %s", oldUsername, newUsername)
100 } else if err != nil {
101 return err
102 }
103 userFolder := path.Join(c.FilesDirectory, oldUsername)
104 newUserFolder := path.Join(c.FilesDirectory, newUsername)
105 err = os.Rename(userFolder, newUserFolder)
106 if err != nil {
107 // This would be bad. User in broken, insecure state.
108 // TODO some sort of better handling?
109 return err
110 }
111 log.Printf("Changed username from %s to %s", oldUsername, newUsername)
112 return nil
113}
114
115func deleteUser(username string) error {
116 _, err := DB.Exec("DELETE FROM user WHERE username = $1", username)
117 if err != nil {
118 return err
119 }
120 username = filepath.Clean(username)
121 err = os.RemoveAll(path.Join(c.FilesDirectory, username))
122 if err != nil {
123 // bad state
124 return err
125 }
126 log.Println("Deleted user", username)
127 return nil
128}