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{}
30var _ repository.AuthRepository = &UserRepository{}
31
32func NewUserRepository(db *gorm.DB) *UserRepository {
33 return &UserRepository{
34 db: db,
35 }
36}
37
38func (self *User) ToModel() *repository.User {
39 return &repository.User{
40 ID: self.Model.ID,
41 Name: self.Name,
42 Username: self.Username,
43 Path: self.Path,
44 IsAdmin: self.IsAdmin,
45 }
46}
47
48func (self Users) ToModel() (users []*repository.User) {
49 for _, user := range self {
50 users = append(users, user.ToModel())
51 }
52 return
53}
54
55// Testing function, will remove later
56// TODO: remove later
57func (self *UserRepository) EnsureAdmin(ctx context.Context) {
58 var exists bool
59 self.db.
60 WithContext(ctx).
61 Model(&User{}).
62 Select("count(*) > 0").
63 Where("username = ?", "admin").
64 Find(&exists)
65
66 if !exists {
67 hash, _ := bcrypt.GenerateFromPassword([]byte("admin"), bcrypt.MinCost)
68 self.db.Save(&User{
69 Username: "admin",
70 Path: "/",
71 IsAdmin: true,
72 Password: string(hash),
73 })
74 }
75}
76
77func (self *UserRepository) List(ctx context.Context) ([]*repository.User, error) {
78 users := Users{}
79 result := self.db.
80 WithContext(ctx).
81 Find(&users)
82
83 if result.Error != nil {
84 return nil, result.Error
85 }
86
87 return users.ToModel(), nil
88}
89
90func (self *UserRepository) Get(ctx context.Context, id uint) (*repository.User, error) {
91 var user = &repository.User{ID: id}
92 result := self.db.
93 WithContext(ctx).
94 First(user)
95
96 if result.Error != nil {
97 return nil, result.Error
98 }
99
100 return user, nil
101}
102
103func (self *UserRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) {
104 userID := struct {
105 ID uint
106 }{}
107
108 result := self.db.
109 WithContext(ctx).
110 Model(&User{}).
111 Where("username = ?", username).
112 First(&userID)
113
114 if result.Error != nil {
115 return 0, result.Error
116 }
117
118 return userID.ID, nil
119}
120
121func (self *UserRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) {
122 userPassword := struct {
123 Password []byte
124 }{}
125
126 result := self.db.
127 WithContext(ctx).
128 Model(&User{}).
129 Where("id = ?", id).
130 First(&userPassword)
131
132 if result.Error != nil {
133 return nil, result.Error
134 }
135
136 return userPassword.Password, nil
137}
138
139func (self *UserRepository) Create(ctx context.Context, createUser *repository.CreateUser) (uint, error) {
140 user := &User{
141 Username: createUser.Username,
142 Name: createUser.Name,
143 Password: string(createUser.Password),
144 }
145
146 result := self.db.
147 WithContext(ctx).
148 Create(user)
149 if result.Error != nil {
150 return 0, result.Error
151 }
152
153 return user.Model.ID, nil
154}
155
156func (self *UserRepository) Update(ctx context.Context, id uint, update *repository.UpdateUser) error {
157 user := &User{
158 Model: gorm.Model{
159 ID: id,
160 },
161 Username: update.Username,
162 Name: update.Name,
163 }
164
165 result := self.db.
166 WithContext(ctx).
167 Save(user)
168 if result.Error != nil {
169 return result.Error
170 }
171
172 return nil
173}
174
175func (self *UserRepository) Delete(ctx context.Context, id uint) error {
176 userID := struct {
177 ID uint
178 }{
179 ID: id,
180 }
181 result := self.db.
182 WithContext(ctx).
183 Delete(userID)
184 if result.Error != nil {
185 return result.Error
186 }
187 return nil
188}
189
190func (u *UserRepository) Any(ctx context.Context) (bool, error) {
191 var exists bool
192 result := u.db.
193 WithContext(ctx).
194 Model(&User{}).
195 Select("count(id) > 0").
196 Find(&exists)
197
198 if result.Error != nil {
199 return false, result.Error
200 }
201
202 return exists, nil
203}