1package sql
2
3import (
4 "context"
5
6 "golang.org/x/crypto/bcrypt"
7 "gorm.io/gorm"
8
9 "git.sr.ht/~gabrielgio/img/pkg/database/repository"
10)
11
12type (
13 User struct {
14 gorm.Model
15 Username string
16 Name string
17 Password string
18 IsAdmin bool
19 Path string
20 }
21
22 Users []*User
23
24 UserRepository struct {
25 db *gorm.DB
26 }
27)
28
29var _ repository.UserRepository = &UserRepository{}
30
31var _ repository.AuthRepository = &UserRepository{}
32
33func NewUserRepository(db *gorm.DB) *UserRepository {
34 return &UserRepository{
35 db: db,
36 }
37}
38
39func (self *User) ToModel() *repository.User {
40 return &repository.User{
41 ID: self.Model.ID,
42 Name: self.Name,
43 Username: self.Username,
44 Path: self.Path,
45 IsAdmin: self.IsAdmin,
46 }
47}
48
49func (self Users) ToModel() (users []*repository.User) {
50 for _, user := range self {
51 users = append(users, user.ToModel())
52 }
53 return
54}
55
56// Testing function, will remove later
57// TODO: remove later
58func (self *UserRepository) EnsureAdmin(ctx context.Context) {
59 var exists bool
60 self.db.
61 WithContext(ctx).
62 Model(&User{}).
63 Select("count(*) > 0").
64 Where("username = ?", "admin").
65 Find(&exists)
66
67 if !exists {
68 hash, _ := bcrypt.GenerateFromPassword([]byte("admin"), bcrypt.MinCost)
69 self.db.Save(&User{
70 Username: "admin",
71 Path: "/",
72 IsAdmin: true,
73 Password: string(hash),
74 })
75 }
76}
77
78func (self *UserRepository) List(ctx context.Context) ([]*repository.User, error) {
79 users := Users{}
80 result := self.db.
81 WithContext(ctx).
82 Find(&users)
83
84 if result.Error != nil {
85 return nil, result.Error
86 }
87
88 return users.ToModel(), nil
89}
90
91func (self *UserRepository) Get(ctx context.Context, id uint) (*repository.User, error) {
92 var user = &repository.User{ID: id}
93 result := self.db.
94 WithContext(ctx).
95 First(user)
96
97 if result.Error != nil {
98 return nil, result.Error
99 }
100
101 return user, nil
102}
103
104func (self *UserRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) {
105 userID := struct {
106 ID uint
107 }{}
108
109 result := self.db.
110 WithContext(ctx).
111 Model(&User{}).
112 Where("username = ?", username).
113 First(&userID)
114
115 if result.Error != nil {
116 return 0, result.Error
117 }
118
119 return userID.ID, nil
120}
121
122func (self *UserRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) {
123 userPassword := struct {
124 Password []byte
125 }{}
126
127 result := self.db.
128 WithContext(ctx).
129 Model(&User{}).
130 Where("id = ?", id).
131 First(&userPassword)
132
133 if result.Error != nil {
134 return nil, result.Error
135 }
136
137 return userPassword.Password, nil
138}
139
140func (self *UserRepository) Create(ctx context.Context, createUser *repository.CreateUser) (uint, error) {
141 user := &User{
142 Username: createUser.Username,
143 Name: createUser.Name,
144 Path: createUser.Path,
145 IsAdmin: createUser.IsAdmin,
146 Password: string(createUser.Password),
147 }
148
149 result := self.db.
150 WithContext(ctx).
151 Create(user)
152 if result.Error != nil {
153 return 0, result.Error
154 }
155
156 return user.Model.ID, nil
157}
158
159func (self *UserRepository) Update(ctx context.Context, id uint, update *repository.UpdateUser) error {
160 user := &User{
161 Model: gorm.Model{
162 ID: id,
163 },
164 Username: update.Username,
165 Name: update.Name,
166 IsAdmin: update.IsAdmin,
167 Path: update.Path,
168 }
169
170 result := self.db.
171 WithContext(ctx).
172 Omit("password").
173 Updates(user)
174 if result.Error != nil {
175 return result.Error
176 }
177
178 return nil
179}
180
181func (self *UserRepository) Delete(ctx context.Context, id uint) error {
182 user := &User{
183 Model: gorm.Model{
184 ID: id,
185 },
186 }
187
188 result := self.db.
189 WithContext(ctx).
190 Delete(user)
191 if result.Error != nil {
192 return result.Error
193 }
194 return nil
195}
196
197func (u *UserRepository) Any(ctx context.Context) (bool, error) {
198 var exists bool
199 result := u.db.
200 WithContext(ctx).
201 Model(&User{}).
202 Select("count(id) > 0").
203 Find(&exists)
204
205 if result.Error != nil {
206 return false, result.Error
207 }
208
209 return exists, nil
210}
211
212func (u *UserRepository) GetPathFromUserID(ctx context.Context, id uint) (string, error) {
213 var userPath string
214
215 result := u.db.
216 WithContext(ctx).
217 Model(&User{}).
218 Select("path").
219 Where("id = ?", id).
220 First(&userPath)
221
222 if result.Error != nil {
223 return "", result.Error
224 }
225
226 return userPath, nil
227}
228
229func (u *UserRepository) UpdatePassword(ctx context.Context, id uint, password []byte) error {
230 result := u.db.
231 WithContext(ctx).
232 Model(&User{}).
233 Where("id = ?", id).
234 Update("password", password)
235
236 return result.Error
237}