opengist/internal/db/user.go

202 lines
4.5 KiB
Go
Raw Normal View History

2023-09-02 22:30:57 +00:00
package db
2023-03-14 15:22:52 +00:00
import (
"gorm.io/gorm"
)
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
Email string
MD5Hash string // for gravatar, if no Email is specified, the value is random
AvatarURL string
GithubID string
2023-12-18 00:35:44 +00:00
GitlabID 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"`
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 {
// 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),
).
UpdateColumn("nb_likes", gorm.Expr("nb_likes - 1")).
Error
if err != nil {
return err
}
// Decrement forks counter for all gists forked by this user
err = tx.Model(&Gist{}).
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),
).
UpdateColumn("nb_forks", gorm.Expr("nb_forks - 1")).
Error
if err != nil {
return err
}
// Delete all gists created by this user
return tx.Where("user_id = ?", user.ID).Delete(&Gist{}).Error
}
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
}
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
}
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
2023-12-18 00:35:44 +00:00
case "gitlab":
err = db.Where("gitlab_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
}
return user, err
}
2023-03-17 13:56:39 +00:00
func (user *User) Create() error {
return db.Create(&user).Error
}
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-12-18 00:35:44 +00:00
providerIDFields := map[string]string{
"github": "github_id",
"gitlab": "gitlab_id",
"gitea": "gitea_id",
"openid-connect": "oidc_id",
}
if providerIDField, ok := providerIDFields[provider]; ok {
2023-09-15 21:56:14 +00:00
return db.Model(&user).
2023-12-18 00:35:44 +00:00
Update(providerIDField, nil).
2023-09-15 21:56:14 +00:00
Update("avatar_url", nil).
Error
}
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,
}
}