1
1
mirror of https://github.com/go-gitea/gitea synced 2025-01-19 06:04:26 +00:00
gitea/models/user/badge.go

236 lines
5.9 KiB
Go
Raw Normal View History

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
import (
"context"
"fmt"
"strings"
"code.gitea.io/gitea/models/db"
"xorm.io/builder"
"xorm.io/xorm"
)
// Badge represents a user badge
type Badge struct {
ID int64 `xorm:"pk autoincr"`
Slug string `xorm:"UNIQUE"`
Description string
ImageURL string
}
// UserBadge represents a user badge
type UserBadge struct { //nolint:revive
ID int64 `xorm:"pk autoincr"`
BadgeID int64
UserID int64 `xorm:"INDEX"`
}
func init() {
db.RegisterModel(new(Badge))
db.RegisterModel(new(UserBadge))
}
// GetUserBadges returns the user's badges.
func GetUserBadges(ctx context.Context, u *User) ([]*Badge, int64, error) {
sess := db.GetEngine(ctx).
Select("`badge`.*").
Join("INNER", "user_badge", "`user_badge`.badge_id=badge.id").
Where("user_badge.user_id=?", u.ID)
badges := make([]*Badge, 0, 8)
count, err := sess.FindAndCount(&badges)
return badges, count, err
}
2024-09-07 22:29:09 -04:00
// GetBadgeUsers returns the users that have a specific badge.
func GetBadgeUsers(ctx context.Context, b *Badge) ([]*User, int64, error) {
sess := db.GetEngine(ctx).
Select("`user`.*").
Join("INNER", "user_badge", "`user_badge`.user_id=user.id").
2024-09-07 22:29:09 -04:00
Join("INNER", "badge", "`user_badge`.badge_id=badge.id").
Where("badge.slug=?", b.Slug)
users := make([]*User, 0, 8)
count, err := sess.FindAndCount(&users)
return users, count, err
}
// CreateBadge creates a new badge.
func CreateBadge(ctx context.Context, badge *Badge) error {
2024-09-07 22:29:09 -04:00
// this will fail if the badge already exists due to the UNIQUE constraint
_, err := db.GetEngine(ctx).Insert(badge)
return err
}
2024-09-07 22:29:09 -04:00
// GetBadge returns a specific badge
func GetBadge(ctx context.Context, slug string) (*Badge, error) {
badge := new(Badge)
has, err := db.GetEngine(ctx).Where("slug=?", slug).Get(badge)
if !has {
return nil, err
}
return badge, err
}
// UpdateBadge updates a badge based on its slug.
func UpdateBadge(ctx context.Context, badge *Badge) error {
2024-09-07 22:29:09 -04:00
_, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Cols("description", "image_url").Update(badge)
return err
}
// DeleteBadge deletes a badge.
func DeleteBadge(ctx context.Context, badge *Badge) error {
_, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Delete(badge)
return err
}
// AddUserBadge adds a badge to a user.
func AddUserBadge(ctx context.Context, u *User, badge *Badge) error {
return AddUserBadges(ctx, u, []*Badge{badge})
}
// AddUserBadges adds badges to a user.
func AddUserBadges(ctx context.Context, u *User, badges []*Badge) error {
return db.WithTx(ctx, func(ctx context.Context) error {
for _, badge := range badges {
// hydrate badge and check if it exists
2024-09-07 22:29:09 -04:00
has, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Get(badge)
if err != nil {
return err
} else if !has {
2024-09-07 22:29:09 -04:00
return ErrBadgeNotExist{Slug: badge.Slug}
}
if err := db.Insert(ctx, &UserBadge{
BadgeID: badge.ID,
UserID: u.ID,
}); err != nil {
return err
}
}
return nil
})
}
// RemoveUserBadge removes a badge from a user.
func RemoveUserBadge(ctx context.Context, u *User, badge *Badge) error {
return RemoveUserBadges(ctx, u, []*Badge{badge})
}
2024-09-07 22:29:09 -04:00
// RemoveUserBadges removes specific badges from a user.
func RemoveUserBadges(ctx context.Context, u *User, badges []*Badge) error {
return db.WithTx(ctx, func(ctx context.Context) error {
for _, badge := range badges {
2024-09-07 22:29:09 -04:00
subQuery := builder.
Select("id").
From("badge").
Where(builder.Eq{"slug": badge.Slug})
if _, err := db.GetEngine(ctx).
Where("`user_badge`.user_id=?", u.ID).
And(builder.In("badge_id", subQuery)).
Delete(&UserBadge{}); err != nil {
return err
}
}
return nil
})
}
// RemoveAllUserBadges removes all badges from a user.
func RemoveAllUserBadges(ctx context.Context, u *User) error {
_, err := db.GetEngine(ctx).Where("user_id=?", u.ID).Delete(&UserBadge{})
return err
}
// SearchBadgeOptions represents the options when fdin badges
type SearchBadgeOptions struct {
db.ListOptions
Keyword string
Slug string
ID int64
OrderBy db.SearchOrderBy
Actor *User // The user doing the search
ExtraParamStrings map[string]string
}
func (opts *SearchBadgeOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.Keyword != "" {
cond = cond.And(builder.Like{"badge.slug", opts.Keyword})
}
return cond
}
func (opts *SearchBadgeOptions) ToOrders() string {
orderBy := "badge.slug"
return orderBy
}
func (opts *SearchBadgeOptions) ToJoins() []db.JoinFunc {
return []db.JoinFunc{
func(e db.Engine) error {
e.Join("INNER", "badge", "badge.badge_id = badge.id")
return nil
},
}
}
func SearchBadges(ctx context.Context, opts *SearchBadgeOptions) (badges []*Badge, _ int64, _ error) {
sessCount := opts.toSearchQueryBase(ctx)
defer sessCount.Close()
count, err := sessCount.Count(new(Badge))
if err != nil {
return nil, 0, fmt.Errorf("count: %w", err)
}
if len(opts.OrderBy) == 0 {
opts.OrderBy = db.SearchOrderByID
}
sessQuery := opts.toSearchQueryBase(ctx).OrderBy(opts.OrderBy.String())
defer sessQuery.Close()
if opts.Page != 0 {
sessQuery = db.SetSessionPagination(sessQuery, opts)
}
// the sql may contain JOIN, so we must only select Badge related columns
sessQuery = sessQuery.Select("`badge`.*")
badges = make([]*Badge, 0, opts.PageSize)
return badges, count, sessQuery.Find(&badges)
}
func (opts *SearchBadgeOptions) toSearchQueryBase(ctx context.Context) *xorm.Session {
var cond builder.Cond
cond = builder.Neq{"id": -1}
if len(opts.Keyword) > 0 {
lowerKeyword := strings.ToLower(opts.Keyword)
keywordCond := builder.Or(
builder.Like{"slug", lowerKeyword},
builder.Like{"description", lowerKeyword},
builder.Like{"id", lowerKeyword},
)
cond = cond.And(keywordCond)
}
if opts.ID > 0 {
cond = cond.And(builder.Eq{"id": opts.ID})
}
if len(opts.Slug) > 0 {
cond = cond.And(builder.Eq{"slug": opts.Slug})
}
e := db.GetEngine(ctx)
return e.Where(cond)
}