blob: e93c03e1a491a99eb0a2582207f2f344a8582282 [file] [log] [blame]
gioa60f0de2024-07-08 10:49:48 +04001package welcome
2
3import (
4 "database/sql"
gio81246f02024-07-10 12:02:15 +04005 "errors"
6
7 "github.com/ncruces/go-sqlite3"
gioa60f0de2024-07-08 10:49:48 +04008
9 "github.com/giolekva/pcloud/core/installer/soft"
10)
11
gio81246f02024-07-10 12:02:15 +040012const (
gio11617ac2024-07-15 16:09:04 +040013 errorConstraintPrimaryKeyViolation = 1555
gio81246f02024-07-10 12:02:15 +040014)
15
16var (
17 ErrorAlreadyExists = errors.New("already exists")
18)
19
gioa60f0de2024-07-08 10:49:48 +040020type Commit struct {
21 Hash string
22 Message string
23}
24
25type Store interface {
gio11617ac2024-07-15 16:09:04 +040026 // TODO(gio): Remove publicKey once auto user sync is implemented
27 CreateUser(username string, password []byte, publicKey, network string) error
gio81246f02024-07-10 12:02:15 +040028 GetUserPassword(username string) ([]byte, error)
gio11617ac2024-07-15 16:09:04 +040029 GetUserNetwork(username string) (string, error)
gioa60f0de2024-07-08 10:49:48 +040030 GetApps() ([]string, error)
gio81246f02024-07-10 12:02:15 +040031 GetUserApps(username string) ([]string, error)
32 CreateApp(name, username string) error
33 GetAppOwner(name string) (string, error)
gioa60f0de2024-07-08 10:49:48 +040034 CreateCommit(name, hash, message string) error
35 GetCommitHistory(name string) ([]Commit, error)
36}
37
38func NewStore(cf soft.RepoIO, db *sql.DB) (Store, error) {
39 s := &storeImpl{cf, db}
40 if err := s.init(); err != nil {
41 return nil, err
42 }
43 return s, nil
44}
45
46type storeImpl struct {
47 cf soft.RepoIO
48 db *sql.DB
49}
50
51func (s *storeImpl) init() error {
52 _, err := s.db.Exec(`
gio81246f02024-07-10 12:02:15 +040053 CREATE TABLE IF NOT EXISTS users (
54 username TEXT PRIMARY KEY,
gio11617ac2024-07-15 16:09:04 +040055 password BLOB,
56 public_key TEXT,
57 network TEXT
gio81246f02024-07-10 12:02:15 +040058 );
gioa60f0de2024-07-08 10:49:48 +040059 CREATE TABLE IF NOT EXISTS apps (
gio81246f02024-07-10 12:02:15 +040060 name TEXT PRIMARY KEY,
61 username TEXT
gioa60f0de2024-07-08 10:49:48 +040062 );
63 CREATE TABLE IF NOT EXISTS commits (
64 app_name TEXT,
65 hash TEXT,
66 message TEXT
67 );
68 `)
69 return err
70
71}
72
gio11617ac2024-07-15 16:09:04 +040073func (s *storeImpl) CreateUser(username string, password []byte, publicKey, network string) error {
74 query := `INSERT INTO users (username, password, public_key, network) VALUES (?, ?, ?, ?)`
75 _, err := s.db.Exec(query, username, password, publicKey, network)
gio81246f02024-07-10 12:02:15 +040076 if err != nil {
77 sqliteErr, ok := err.(*sqlite3.Error)
gio11617ac2024-07-15 16:09:04 +040078 if ok && sqliteErr.ExtendedCode() == errorConstraintPrimaryKeyViolation {
gio81246f02024-07-10 12:02:15 +040079 return ErrorAlreadyExists
80 }
81 }
gioa60f0de2024-07-08 10:49:48 +040082 return err
83}
84
gio81246f02024-07-10 12:02:15 +040085func (s *storeImpl) GetUserPassword(username string) ([]byte, error) {
86 query := `SELECT password FROM users WHERE username = ?`
87 row := s.db.QueryRow(query, username)
88 if err := row.Err(); err != nil {
89 return nil, err
90 }
91 ret := []byte{}
92 if err := row.Scan(&ret); err != nil {
93 return nil, err
94 }
95 return ret, nil
96}
97
gio11617ac2024-07-15 16:09:04 +040098func (s *storeImpl) GetUserNetwork(username string) (string, error) {
99 query := `SELECT network FROM users WHERE username = ?`
100 row := s.db.QueryRow(query, username)
101 if err := row.Err(); err != nil {
102 return "", err
103 }
104 var ret string
105 if err := row.Scan(&ret); err != nil {
106 if errors.Is(sql.ErrNoRows, err) {
107 return "", nil
108 }
109 return "", err
110 }
111 return ret, nil
112}
113
gio81246f02024-07-10 12:02:15 +0400114func (s *storeImpl) CreateApp(name, username string) error {
115 query := `INSERT INTO apps (name, username) VALUES (?, ?)`
116 _, err := s.db.Exec(query, name, username)
117 return err
118}
119
120func (s *storeImpl) GetAppOwner(name string) (string, error) {
121 query := `SELECT username FROM apps WHERE name = ?`
122 row := s.db.QueryRow(query, name)
123 if err := row.Err(); err != nil {
124 return "", err
125 }
126 var ret string
127 if err := row.Scan(&ret); err != nil {
128 return "", err
129 }
130 return ret, nil
131}
132
gioa60f0de2024-07-08 10:49:48 +0400133func (s *storeImpl) GetApps() ([]string, error) {
134 query := `SELECT name FROM apps`
135 rows, err := s.db.Query(query)
136 if err != nil {
137 return nil, err
138 }
139 defer rows.Close()
140 ret := []string{}
141 for rows.Next() {
142 if err := rows.Err(); err != nil {
143 return nil, err
144 }
145 var name string
146 if err := rows.Scan(&name); err != nil {
147 return nil, err
148 }
149 ret = append(ret, name)
150
151 }
152 return ret, nil
153}
154
gio81246f02024-07-10 12:02:15 +0400155func (s *storeImpl) GetUserApps(username string) ([]string, error) {
156 query := `SELECT name FROM apps WHERE username = ?`
157 rows, err := s.db.Query(query, username)
158 if err != nil {
159 return nil, err
160 }
161 defer rows.Close()
162 ret := []string{}
163 for rows.Next() {
164 if err := rows.Err(); err != nil {
165 return nil, err
166 }
167 var name string
168 if err := rows.Scan(&name); err != nil {
169 return nil, err
170 }
171 ret = append(ret, name)
172
173 }
174 return ret, nil
175}
176
gioa60f0de2024-07-08 10:49:48 +0400177func (s *storeImpl) CreateCommit(name, hash, message string) error {
178 query := `INSERT INTO commits (app_name, hash, message) VALUES (?, ?, ?)`
179 _, err := s.db.Exec(query, name, hash, message)
180 return err
181}
182
183func (s *storeImpl) GetCommitHistory(name string) ([]Commit, error) {
184 query := `SELECT hash, message FROM commits WHERE app_name = ?`
185 rows, err := s.db.Query(query, name)
186 if err != nil {
187 return nil, err
188 }
189 defer rows.Close()
190 ret := []Commit{}
191 for rows.Next() {
192 if err := rows.Err(); err != nil {
193 return nil, err
194 }
195 var c Commit
196 if err := rows.Scan(&c.Hash, &c.Message); err != nil {
197 return nil, err
198 }
199 ret = append(ret, c)
200
201 }
202 return ret, nil
203}