db.go (view raw)
1package main
2
3import (
4 "crypto/rand"
5 "database/sql"
6 "io"
7 "io/ioutil"
8 "log"
9 mathrand "math/rand"
10 "os"
11 "path"
12 "path/filepath"
13 "sort"
14 "time"
15)
16
17var DB *sql.DB
18
19func initializeDB() {
20 var err error
21 DB, err = sql.Open("sqlite3", c.DBFile)
22 if err != nil {
23 log.Fatal(err)
24 }
25 createTablesIfDNE()
26}
27
28type File struct { // also folders
29 Creator string
30 Name string // includes folder
31 UpdatedTime time.Time
32 TimeAgo string
33 IsText bool
34 Children []File
35 Host string
36}
37
38func fileFromPath(fullPath string) File {
39 info, _ := os.Stat(fullPath)
40 creatorFolder := getCreator(fullPath)
41 isText := isTextFile(fullPath)
42 updatedTime := info.ModTime()
43 return File{
44 Name: getLocalPath(fullPath),
45 Creator: path.Base(creatorFolder),
46 UpdatedTime: updatedTime,
47 IsText: isText,
48 TimeAgo: timeago(&updatedTime),
49 Host: c.Host,
50 }
51
52}
53
54type User struct {
55 Username string
56 Email string
57 Active bool
58 Admin bool
59 CreatedAt int // timestamp
60 Reference string
61}
62
63// returns in a random order
64func getActiveUserNames() ([]string, error) {
65 rows, err := DB.Query(`SELECT username from user WHERE active is true`)
66 if err != nil {
67 return nil, err
68 }
69 var users []string
70 for rows.Next() {
71 var user string
72 err = rows.Scan(&user)
73 if err != nil {
74 return nil, err
75 }
76 users = append(users, user)
77 }
78
79 dest := make([]string, len(users))
80 perm := mathrand.Perm(len(users))
81 for i, v := range perm {
82 dest[v] = users[i]
83 }
84 return dest, nil
85}
86
87func getUserByName(username string) (*User, error) {
88 var user User
89 row := DB.QueryRow(`SELECT username, email, active, admin, created_at, reference from user WHERE username = ?`, username)
90 err := row.Scan(&user.Username, &user.Email, &user.Active, &user.Admin, &user.CreatedAt, &user.Reference)
91 if err != nil {
92 return nil, err
93 }
94 return &user, nil
95}
96
97func getUsers() ([]User, error) {
98 rows, err := DB.Query(`SELECT username, email, active, admin, created_at, reference from user ORDER BY created_at DESC`)
99 if err != nil {
100 return nil, err
101 }
102 var users []User
103 for rows.Next() {
104 var user User
105 err = rows.Scan(&user.Username, &user.Email, &user.Active, &user.Admin, &user.CreatedAt, &user.Reference)
106 if err != nil {
107 return nil, err
108 }
109 users = append(users, user)
110 }
111 return users, nil
112}
113
114func getIndexFiles(admin bool) ([]*File, error) { // cache this function
115 result := []*File{}
116 err := filepath.Walk(c.FilesDirectory, func(thepath string, info os.FileInfo, err error) error {
117 if err != nil {
118 log.Printf("Failure accessing a path %q: %v\n", thepath, err)
119 return err // think about
120 }
121 if !admin && info.IsDir() && info.Name() == HiddenFolder {
122 return filepath.SkipDir
123 }
124 // make this do what it should
125 if !info.IsDir() {
126 res := fileFromPath(thepath)
127 result = append(result, &res)
128 }
129 return nil
130 })
131 if err != nil {
132 return nil, err
133 }
134 sort.Slice(result, func(i, j int) bool {
135 return result[i].UpdatedTime.After(result[j].UpdatedTime)
136 })
137 if len(result) > 50 {
138 result = result[:50]
139 }
140 return result, nil
141} // todo clean up paths
142
143func getMyFilesRecursive(p string, creator string) ([]File, error) {
144 result := []File{}
145 files, err := ioutil.ReadDir(p)
146 if err != nil {
147 return nil, err
148 }
149 for _, file := range files {
150 fullPath := path.Join(p, file.Name())
151 f := fileFromPath(fullPath)
152 if file.IsDir() {
153 f.Children, err = getMyFilesRecursive(path.Join(p, file.Name()), creator)
154 }
155 result = append(result, f)
156 }
157 return result, nil
158}
159
160func createTablesIfDNE() {
161 _, err := DB.Exec(`CREATE TABLE IF NOT EXISTS user (
162 id INTEGER PRIMARY KEY NOT NULL,
163 username TEXT NOT NULL UNIQUE,
164 email TEXT NOT NULL UNIQUE,
165 password_hash TEXT NOT NULL,
166 reference TEXT NOT NULL default "",
167 active boolean NOT NULL DEFAULT false,
168 admin boolean NOT NULL DEFAULT false,
169 created_at INTEGER DEFAULT (strftime('%s', 'now'))
170);
171
172CREATE TABLE IF NOT EXISTS cookie_key (
173 value TEXT NOT NULL
174);`)
175 if err != nil {
176 log.Fatal(err)
177 }
178}
179
180// Generate a cryptographically secure key for the cookie store
181func generateCookieKeyIfDNE() []byte {
182 rows, err := DB.Query("SELECT value FROM cookie_key LIMIT 1")
183 defer rows.Close()
184 if err != nil {
185 log.Fatal(err)
186 }
187 if rows.Next() {
188 var cookie []byte
189 err := rows.Scan(&cookie)
190 if err != nil {
191 log.Fatal(err)
192 }
193 return cookie
194 } else {
195 k := make([]byte, 32)
196 _, err := io.ReadFull(rand.Reader, k)
197 if err != nil {
198 log.Fatal(err)
199 }
200 _, err = DB.Exec("insert into cookie_key values (?)", k)
201 if err != nil {
202 log.Fatal(err)
203 }
204 return k
205 }
206}