blob: 3f8428d998b31148e0331b1bb649d7a5ffe3c098 [file] [log] [blame]
gioa60f0de2024-07-08 10:49:48 +04001package welcome
2
3import (
giob4a3a192024-08-19 09:55:47 +04004 "bytes"
gioa60f0de2024-07-08 10:49:48 +04005 "database/sql"
giob4a3a192024-08-19 09:55:47 +04006 "encoding/json"
gio81246f02024-07-10 12:02:15 +04007 "errors"
8
9 "github.com/ncruces/go-sqlite3"
gioa60f0de2024-07-08 10:49:48 +040010
giob4a3a192024-08-19 09:55:47 +040011 "github.com/giolekva/pcloud/core/installer"
gioa60f0de2024-07-08 10:49:48 +040012 "github.com/giolekva/pcloud/core/installer/soft"
13)
14
gio81246f02024-07-10 12:02:15 +040015const (
gio11617ac2024-07-15 16:09:04 +040016 errorConstraintPrimaryKeyViolation = 1555
gio81246f02024-07-10 12:02:15 +040017)
18
19var (
20 ErrorAlreadyExists = errors.New("already exists")
21)
22
giob4a3a192024-08-19 09:55:47 +040023type CommitMeta struct {
gioe2e31e12024-08-18 08:20:56 +040024 Status string
giob4a3a192024-08-19 09:55:47 +040025 Error string
26 Hash string
gioa60f0de2024-07-08 10:49:48 +040027 Message string
28}
29
giob4a3a192024-08-19 09:55:47 +040030type Commit struct {
31 CommitMeta
32 Resources installer.ReleaseResources
33}
34
gioa60f0de2024-07-08 10:49:48 +040035type Store interface {
giocafd4e62024-07-31 10:53:40 +040036 CreateUser(username string, password []byte, network string) error
gio81246f02024-07-10 12:02:15 +040037 GetUserPassword(username string) ([]byte, error)
gio11617ac2024-07-15 16:09:04 +040038 GetUserNetwork(username string) (string, error)
gioa60f0de2024-07-08 10:49:48 +040039 GetApps() ([]string, error)
gio81246f02024-07-10 12:02:15 +040040 GetUserApps(username string) ([]string, error)
41 CreateApp(name, username string) error
42 GetAppOwner(name string) (string, error)
gio7fbd4ad2024-08-27 10:06:39 +040043 CreateCommit(name, branch, hash, message, status, error string, resources []byte) error
44 GetCommitHistory(name, branch string) ([]CommitMeta, error)
giob4a3a192024-08-19 09:55:47 +040045 GetCommit(hash string) (Commit, error)
gio7fbd4ad2024-08-27 10:06:39 +040046 GetBranches(name string) ([]string, error)
gioa60f0de2024-07-08 10:49:48 +040047}
48
49func NewStore(cf soft.RepoIO, db *sql.DB) (Store, error) {
50 s := &storeImpl{cf, db}
51 if err := s.init(); err != nil {
52 return nil, err
53 }
54 return s, nil
55}
56
57type storeImpl struct {
58 cf soft.RepoIO
59 db *sql.DB
60}
61
62func (s *storeImpl) init() error {
63 _, err := s.db.Exec(`
gio81246f02024-07-10 12:02:15 +040064 CREATE TABLE IF NOT EXISTS users (
65 username TEXT PRIMARY KEY,
gio11617ac2024-07-15 16:09:04 +040066 password BLOB,
gio11617ac2024-07-15 16:09:04 +040067 network TEXT
gio81246f02024-07-10 12:02:15 +040068 );
gioa60f0de2024-07-08 10:49:48 +040069 CREATE TABLE IF NOT EXISTS apps (
gio81246f02024-07-10 12:02:15 +040070 name TEXT PRIMARY KEY,
71 username TEXT
gioa60f0de2024-07-08 10:49:48 +040072 );
73 CREATE TABLE IF NOT EXISTS commits (
74 app_name TEXT,
gio7fbd4ad2024-08-27 10:06:39 +040075 branch TEXT,
gioa60f0de2024-07-08 10:49:48 +040076 hash TEXT,
gioe2e31e12024-08-18 08:20:56 +040077 message TEXT,
giob4a3a192024-08-19 09:55:47 +040078 status TEXT,
79 error TEXT,
80 resources JSONB
gioa60f0de2024-07-08 10:49:48 +040081 );
82 `)
83 return err
84
85}
86
giocafd4e62024-07-31 10:53:40 +040087func (s *storeImpl) CreateUser(username string, password []byte, network string) error {
88 query := `INSERT INTO users (username, password, network) VALUES (?, ?, ?)`
89 _, err := s.db.Exec(query, username, password, network)
gio81246f02024-07-10 12:02:15 +040090 if err != nil {
91 sqliteErr, ok := err.(*sqlite3.Error)
gio11617ac2024-07-15 16:09:04 +040092 if ok && sqliteErr.ExtendedCode() == errorConstraintPrimaryKeyViolation {
gio81246f02024-07-10 12:02:15 +040093 return ErrorAlreadyExists
94 }
95 }
gioa60f0de2024-07-08 10:49:48 +040096 return err
97}
98
gio81246f02024-07-10 12:02:15 +040099func (s *storeImpl) GetUserPassword(username string) ([]byte, error) {
100 query := `SELECT password FROM users WHERE username = ?`
101 row := s.db.QueryRow(query, username)
102 if err := row.Err(); err != nil {
103 return nil, err
104 }
105 ret := []byte{}
106 if err := row.Scan(&ret); err != nil {
107 return nil, err
108 }
109 return ret, nil
110}
111
gio11617ac2024-07-15 16:09:04 +0400112func (s *storeImpl) GetUserNetwork(username string) (string, error) {
113 query := `SELECT network FROM users WHERE username = ?`
114 row := s.db.QueryRow(query, username)
115 if err := row.Err(); err != nil {
116 return "", err
117 }
118 var ret string
119 if err := row.Scan(&ret); err != nil {
120 if errors.Is(sql.ErrNoRows, err) {
121 return "", nil
122 }
123 return "", err
124 }
125 return ret, nil
126}
127
gio81246f02024-07-10 12:02:15 +0400128func (s *storeImpl) CreateApp(name, username string) error {
129 query := `INSERT INTO apps (name, username) VALUES (?, ?)`
130 _, err := s.db.Exec(query, name, username)
131 return err
132}
133
134func (s *storeImpl) GetAppOwner(name string) (string, error) {
135 query := `SELECT username FROM apps WHERE name = ?`
136 row := s.db.QueryRow(query, name)
137 if err := row.Err(); err != nil {
138 return "", err
139 }
140 var ret string
141 if err := row.Scan(&ret); err != nil {
142 return "", err
143 }
144 return ret, nil
145}
146
gioa60f0de2024-07-08 10:49:48 +0400147func (s *storeImpl) GetApps() ([]string, error) {
148 query := `SELECT name FROM apps`
149 rows, err := s.db.Query(query)
150 if err != nil {
151 return nil, err
152 }
153 defer rows.Close()
154 ret := []string{}
155 for rows.Next() {
156 if err := rows.Err(); err != nil {
157 return nil, err
158 }
159 var name string
160 if err := rows.Scan(&name); err != nil {
161 return nil, err
162 }
163 ret = append(ret, name)
164
165 }
166 return ret, nil
167}
168
gio81246f02024-07-10 12:02:15 +0400169func (s *storeImpl) GetUserApps(username string) ([]string, error) {
170 query := `SELECT name FROM apps WHERE username = ?`
171 rows, err := s.db.Query(query, username)
172 if err != nil {
173 return nil, err
174 }
175 defer rows.Close()
176 ret := []string{}
177 for rows.Next() {
178 if err := rows.Err(); err != nil {
179 return nil, err
180 }
181 var name string
182 if err := rows.Scan(&name); err != nil {
183 return nil, err
184 }
185 ret = append(ret, name)
186
187 }
188 return ret, nil
189}
190
gio7fbd4ad2024-08-27 10:06:39 +0400191func (s *storeImpl) CreateCommit(name, branch, hash, message, status, error string, resources []byte) error {
192 query := `INSERT INTO commits (app_name, branch, hash, message, status, error, resources) VALUES (?, ?, ?, ?, ?, ?, ?)`
193 _, err := s.db.Exec(query, name, branch, hash, message, status, error, resources)
gioa60f0de2024-07-08 10:49:48 +0400194 return err
195}
196
gio7fbd4ad2024-08-27 10:06:39 +0400197func (s *storeImpl) GetCommitHistory(name, branch string) ([]CommitMeta, error) {
198 query := `SELECT hash, message, status, error FROM commits WHERE app_name = ? AND branch = ?`
199 rows, err := s.db.Query(query, name, branch)
gioa60f0de2024-07-08 10:49:48 +0400200 if err != nil {
201 return nil, err
202 }
203 defer rows.Close()
giob4a3a192024-08-19 09:55:47 +0400204 ret := []CommitMeta{}
gioa60f0de2024-07-08 10:49:48 +0400205 for rows.Next() {
206 if err := rows.Err(); err != nil {
207 return nil, err
208 }
giob4a3a192024-08-19 09:55:47 +0400209 var c CommitMeta
210 if err := rows.Scan(&c.Hash, &c.Message, &c.Status, &c.Error); err != nil {
gioa60f0de2024-07-08 10:49:48 +0400211 return nil, err
212 }
213 ret = append(ret, c)
214
215 }
216 return ret, nil
217}
giob4a3a192024-08-19 09:55:47 +0400218
219func (s *storeImpl) GetCommit(hash string) (Commit, error) {
220 query := `SELECT hash, message, status, error, resources FROM commits WHERE hash = ?`
221 row := s.db.QueryRow(query, hash)
222 if err := row.Err(); err != nil {
223 return Commit{}, err
224 }
225 var ret Commit
226 var c Commit
227 var res []byte
228 if err := row.Scan(&c.Hash, &c.Message, &c.Status, &c.Error, &res); err != nil {
229 return Commit{}, err
230 }
231 if err := json.NewDecoder(bytes.NewBuffer(res)).Decode(&ret.Resources); err != nil {
232 return Commit{}, err
233 }
234 return ret, nil
235}
gio7fbd4ad2024-08-27 10:06:39 +0400236
237func (s *storeImpl) GetBranches(name string) ([]string, error) {
238 query := `SELECT DISTINCT branch FROM commits WHERE app_name = ?`
239 rows, err := s.db.Query(query, name)
240 if err != nil {
241 return nil, err
242 }
243 defer rows.Close()
244 ret := []string{}
245 for rows.Next() {
246 if err := rows.Err(); err != nil {
247 return nil, err
248 }
249 var b string
250 if err := rows.Scan(&b); err != nil {
251 return nil, err
252 }
253 ret = append(ret, b)
254
255 }
256 return ret, nil
257}