2023-09-02 22:30:57 +00:00
|
|
|
package db
|
2023-03-14 15:22:52 +00:00
|
|
|
|
2023-03-14 23:52:24 +00:00
|
|
|
import (
|
|
|
|
"gorm.io/gorm"
|
|
|
|
)
|
2023-03-14 16:05:21 +00:00
|
|
|
|
2023-03-14 15:22:52 +00:00
|
|
|
type User struct {
|
|
|
|
ID uint `gorm:"primaryKey"`
|
2023-03-17 13:56:39 +00:00
|
|
|
Username string `gorm:"uniqueIndex"`
|
|
|
|
Password string
|
2023-03-14 15:22:52 +00:00
|
|
|
IsAdmin bool
|
|
|
|
CreatedAt int64
|
2023-03-19 15:29:14 +00:00
|
|
|
Email string
|
|
|
|
MD5Hash string // for gravatar, if no Email is specified, the value is random
|
2023-05-26 07:15:37 +00:00
|
|
|
AvatarURL string
|
2023-04-17 12:25:39 +00:00
|
|
|
GithubID string
|
|
|
|
GiteaID string
|
2023-09-15 21:56:14 +00:00
|
|
|
OIDCID string `gorm:"column:oidc_id"`
|
2023-03-14 15:22:52 +00:00
|
|
|
|
|
|
|
Gists []Gist `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;foreignKey:UserID"`
|
2023-04-18 00:33:19 +00:00
|
|
|
SSHKeys []SSHKey `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;foreignKey:UserID"`
|
2023-03-14 15:22:52 +00:00
|
|
|
Liked []Gist `gorm:"many2many:likes;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
|
|
|
}
|
|
|
|
|
2023-03-17 13:56:39 +00:00
|
|
|
func (user *User) BeforeDelete(tx *gorm.DB) error {
|
2023-03-14 23:52:24 +00:00
|
|
|
// Decrement likes counter for all gists liked by this user
|
|
|
|
// The likes will be automatically deleted by the foreign key constraint
|
|
|
|
err := tx.Model(&Gist{}).
|
|
|
|
Omit("updated_at").
|
|
|
|
Where("id IN (?)", tx.
|
|
|
|
Select("gist_id").
|
|
|
|
Table("likes").
|
2023-03-17 13:56:39 +00:00
|
|
|
Where("user_id = ?", user.ID),
|
2023-03-14 23:52:24 +00:00
|
|
|
).
|
|
|
|
UpdateColumn("nb_likes", gorm.Expr("nb_likes - 1")).
|
|
|
|
Error
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decrement forks counter for all gists forked by this user
|
2023-09-25 16:43:36 +00:00
|
|
|
err = tx.Model(&Gist{}).
|
2023-03-14 23:52:24 +00:00
|
|
|
Omit("updated_at").
|
|
|
|
Where("id IN (?)", tx.
|
|
|
|
Select("forked_id").
|
|
|
|
Table("gists").
|
2023-03-17 13:56:39 +00:00
|
|
|
Where("user_id = ?", user.ID),
|
2023-03-14 23:52:24 +00:00
|
|
|
).
|
|
|
|
UpdateColumn("nb_forks", gorm.Expr("nb_forks - 1")).
|
|
|
|
Error
|
2023-09-25 16:43:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete all gists created by this user
|
|
|
|
return tx.Where("user_id = ?", user.ID).Delete(&Gist{}).Error
|
2023-03-14 23:52:24 +00:00
|
|
|
}
|
|
|
|
|
2023-03-17 13:56:39 +00:00
|
|
|
func UserExists(username string) (bool, error) {
|
|
|
|
var count int64
|
|
|
|
err := db.Model(&User{}).Where("username like ?", username).Count(&count).Error
|
|
|
|
return count > 0, err
|
2023-03-14 15:22:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func GetAllUsers(offset int) ([]*User, error) {
|
2023-03-17 13:56:39 +00:00
|
|
|
var users []*User
|
2023-03-14 15:22:52 +00:00
|
|
|
err := db.
|
|
|
|
Limit(11).
|
|
|
|
Offset(offset * 10).
|
|
|
|
Order("id asc").
|
2023-03-17 13:56:39 +00:00
|
|
|
Find(&users).Error
|
2023-03-14 15:22:52 +00:00
|
|
|
|
2023-03-17 13:56:39 +00:00
|
|
|
return users, err
|
2023-03-14 15:22:52 +00:00
|
|
|
}
|
|
|
|
|
2023-03-17 13:56:39 +00:00
|
|
|
func GetUserByUsername(username string) (*User, error) {
|
|
|
|
user := new(User)
|
|
|
|
err := db.
|
|
|
|
Where("username like ?", username).
|
2023-03-14 15:22:52 +00:00
|
|
|
First(&user).Error
|
2023-03-17 13:56:39 +00:00
|
|
|
return user, err
|
2023-03-14 15:22:52 +00:00
|
|
|
}
|
|
|
|
|
2023-03-17 13:56:39 +00:00
|
|
|
func GetUserById(userId uint) (*User, error) {
|
|
|
|
user := new(User)
|
|
|
|
err := db.
|
|
|
|
Where("id = ?", userId).
|
2023-03-14 15:22:52 +00:00
|
|
|
First(&user).Error
|
2023-03-17 13:56:39 +00:00
|
|
|
return user, err
|
2023-03-14 15:22:52 +00:00
|
|
|
}
|
|
|
|
|
2023-05-26 07:15:37 +00:00
|
|
|
func GetUsersFromEmails(emailsSet map[string]struct{}) (map[string]*User, error) {
|
|
|
|
var users []*User
|
|
|
|
|
|
|
|
emails := make([]string, 0, len(emailsSet))
|
|
|
|
for email := range emailsSet {
|
|
|
|
emails = append(emails, email)
|
|
|
|
}
|
|
|
|
|
|
|
|
err := db.
|
|
|
|
Where("email IN ?", emails).
|
|
|
|
Find(&users).Error
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
userMap := make(map[string]*User)
|
|
|
|
for _, user := range users {
|
|
|
|
userMap[user.Email] = user
|
|
|
|
}
|
|
|
|
|
|
|
|
return userMap, nil
|
|
|
|
}
|
|
|
|
|
2023-05-01 00:55:34 +00:00
|
|
|
func SSHKeyExistsForUser(sshKey string, userId uint) (*SSHKey, error) {
|
|
|
|
key := new(SSHKey)
|
2023-03-14 15:22:52 +00:00
|
|
|
err := db.
|
2023-05-01 00:55:34 +00:00
|
|
|
Where("content = ?", sshKey).
|
|
|
|
Where("user_id = ?", userId).
|
|
|
|
First(&key).Error
|
2023-03-14 15:22:52 +00:00
|
|
|
|
2023-05-01 00:55:34 +00:00
|
|
|
return key, err
|
2023-03-14 15:22:52 +00:00
|
|
|
}
|
|
|
|
|
2023-04-17 12:25:39 +00:00
|
|
|
func GetUserByProvider(id string, provider string) (*User, error) {
|
|
|
|
user := new(User)
|
|
|
|
var err error
|
|
|
|
switch provider {
|
|
|
|
case "github":
|
|
|
|
err = db.Where("github_id = ?", id).First(&user).Error
|
|
|
|
case "gitea":
|
|
|
|
err = db.Where("gitea_id = ?", id).First(&user).Error
|
2023-09-15 21:56:14 +00:00
|
|
|
case "openid-connect":
|
|
|
|
err = db.Where("oidc_id = ?", id).First(&user).Error
|
2023-04-17 12:25:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return user, err
|
|
|
|
}
|
|
|
|
|
2023-03-17 13:56:39 +00:00
|
|
|
func (user *User) Create() error {
|
|
|
|
return db.Create(&user).Error
|
|
|
|
}
|
|
|
|
|
2023-03-19 15:29:14 +00:00
|
|
|
func (user *User) Update() error {
|
|
|
|
return db.Save(&user).Error
|
|
|
|
}
|
|
|
|
|
2023-03-17 13:56:39 +00:00
|
|
|
func (user *User) Delete() error {
|
|
|
|
return db.Delete(&user).Error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (user *User) SetAdmin() error {
|
|
|
|
return db.Model(&user).Update("is_admin", true).Error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (user *User) HasLiked(gist *Gist) (bool, error) {
|
2023-03-14 15:22:52 +00:00
|
|
|
association := db.Model(&gist).Where("user_id = ?", user.ID).Association("Likes")
|
|
|
|
if association.Error != nil {
|
|
|
|
return false, association.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
if association.Count() == 0 {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
}
|
2023-03-17 13:56:39 +00:00
|
|
|
|
2023-04-17 17:11:32 +00:00
|
|
|
func (user *User) DeleteProviderID(provider string) error {
|
2023-04-17 12:25:39 +00:00
|
|
|
switch provider {
|
|
|
|
case "github":
|
2023-05-26 07:15:37 +00:00
|
|
|
return db.Model(&user).
|
|
|
|
Update("github_id", nil).
|
|
|
|
Update("avatar_url", nil).
|
|
|
|
Error
|
2023-04-17 12:25:39 +00:00
|
|
|
case "gitea":
|
2023-05-26 07:15:37 +00:00
|
|
|
return db.Model(&user).
|
|
|
|
Update("gitea_id", nil).
|
|
|
|
Update("avatar_url", nil).
|
|
|
|
Error
|
2023-09-15 21:56:14 +00:00
|
|
|
case "openid-connect":
|
|
|
|
return db.Model(&user).
|
|
|
|
Update("oidc_id", nil).
|
|
|
|
Update("avatar_url", nil).
|
|
|
|
Error
|
2023-04-17 12:25:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-17 13:56:39 +00:00
|
|
|
// -- DTO -- //
|
|
|
|
|
|
|
|
type UserDTO struct {
|
|
|
|
Username string `form:"username" validate:"required,max=24,alphanum,notreserved"`
|
|
|
|
Password string `form:"password" validate:"required"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (dto *UserDTO) ToUser() *User {
|
|
|
|
return &User{
|
|
|
|
Username: dto.Username,
|
|
|
|
Password: dto.Password,
|
|
|
|
}
|
|
|
|
}
|