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/components/auth"
10 "git.sr.ht/~gabrielgio/img/pkg/components/user"
11)
12
13type (
14 User struct {
15 gorm.Model
16 Username string
17 Name string
18 Password string
19 IsAdmin bool
20 Path string
21 }
22
23 Users []*User
24
25 UserRepository struct {
26 db *gorm.DB
27 }
28)
29
30var _ auth.Repository = &UserRepository{}
31var _ user.Repository = &UserRepository{}
32
33func NewUserRepository(db *gorm.DB) *UserRepository {
34 return &UserRepository{
35 db: db,
36 }
37}
38
39func (self *User) ToModel() *user.User {
40 return &user.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 []*user.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) ([]*user.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) (*user.User, error) {
92 var user = &user.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 *user.CreateUser) error {
141 user := &User{
142 Username: createUser.Username,
143 Name: createUser.Name,
144 Password: string(createUser.Password),
145 }
146
147 result := self.db.
148 WithContext(ctx).
149 Create(user)
150 if result.Error != nil {
151 return result.Error
152 }
153
154 return nil
155}
156
157func (self *UserRepository) Update(ctx context.Context, id uint, update *user.UpdateUser) error {
158 user := &User{
159 Model: gorm.Model{
160 ID: id,
161 },
162 Username: update.Username,
163 Name: update.Name,
164 }
165
166 result := self.db.
167 WithContext(ctx).
168 Save(user)
169 if result.Error != nil {
170 return result.Error
171 }
172
173 return nil
174}
175
176func (self *UserRepository) Delete(ctx context.Context, id uint) error {
177 userID := struct {
178 ID uint
179 }{
180 ID: id,
181 }
182 result := self.db.
183 WithContext(ctx).
184 Delete(userID)
185 if result.Error != nil {
186 return result.Error
187 }
188 return nil
189}
190
191func (u *UserRepository) Any(ctx context.Context) (bool, error) {
192 var exists bool
193 result := u.db.
194 WithContext(ctx).
195 Model(&User{}).
196 Select("count(id) > 0").
197 Find(&exists)
198
199 if result.Error != nil {
200 return false, result.Error
201 }
202
203 return exists, nil
204}