Files
gitea/models/user/badge.go
silverwind aba87285f0 Remove dead code identified by deadcode tool (#37271)
Ran [`deadcode`](https://pkg.go.dev/golang.org/x/tools/cmd/deadcode)
(`-test ./...`) to find functions, methods and error types unreachable
from any call path (including tests), and removed the truly-dead ones.

Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-20 07:52:48 +00:00

255 lines
7.1 KiB
Go

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
import (
"context"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
"xorm.io/xorm/schemas"
)
// 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 // export stutter
ID int64 `xorm:"pk autoincr"`
BadgeID int64
UserID int64
}
// TableIndices implements xorm's TableIndices interface
func (n *UserBadge) TableIndices() []*schemas.Index {
indices := make([]*schemas.Index, 0, 1)
ubUnique := schemas.NewIndex("unique_user_badge", schemas.UniqueType)
ubUnique.AddColumn("user_id", "badge_id")
indices = append(indices, ubUnique)
return indices
}
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
}
// GetBadgeUsersOptions contains options for getting users with a specific badge
type GetBadgeUsersOptions struct {
db.ListOptions
BadgeSlug string
}
// GetBadgeUsers returns the users that have a specific badge with pagination support.
func GetBadgeUsers(ctx context.Context, opts *GetBadgeUsersOptions) ([]*User, int64, error) {
sess := db.GetEngine(ctx).
Select("`user`.*").
Join("INNER", "user_badge", "`user_badge`.user_id=user.id").
Join("INNER", "badge", "`user_badge`.badge_id=badge.id").
Where("badge.slug=?", opts.BadgeSlug)
if opts.Page > 0 {
sess = db.SetSessionPagination(sess, opts)
}
users := make([]*User, 0, opts.PageSize)
count, err := sess.FindAndCount(&users)
return users, count, err
}
// CreateBadge creates a new badge.
func CreateBadge(ctx context.Context, badge *Badge) error {
exists, err := db.GetEngine(ctx).Where("slug = ?", badge.Slug).Exist(new(Badge))
if err != nil {
return err
}
if exists {
return util.NewAlreadyExistErrorf("badge already exists [slug: %s]", badge.Slug)
}
if _, err := db.GetEngine(ctx).Insert(badge); err != nil {
// Handle race between existence check and insert.
exists, existErr := db.GetEngine(ctx).Where("slug = ?", badge.Slug).Exist(new(Badge))
if existErr == nil && exists {
return util.NewAlreadyExistErrorf("badge already exists [slug: %s]", badge.Slug)
}
return err
}
return nil
}
// 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 err != nil {
return nil, err
}
if !has {
return nil, util.NewNotExistErrorf("badge does not exist [slug: %s]", slug)
}
return badge, nil
}
// UpdateBadge updates a badge based on its slug.
func UpdateBadge(ctx context.Context, badge *Badge) error {
_, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Cols("description", "image_url").Update(badge)
return err
}
// DeleteBadge deletes a badge and all associated user_badge entries.
func DeleteBadge(ctx context.Context, badge *Badge) error {
return db.WithTx(ctx, func(ctx context.Context) error {
// First delete all user_badge entries for this badge
if _, err := db.GetEngine(ctx).
Where("badge_id = ?", badge.ID).
Delete(&UserBadge{}); err != nil {
return err
}
// Then delete the badge itself
if _, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Delete(badge); err != nil {
return err
}
return nil
})
}
// 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
has, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Get(badge)
if err != nil {
return err
} else if !has {
return util.NewNotExistErrorf("badge does not exist [slug: %s]", badge.Slug)
}
exists, err := db.GetEngine(ctx).Where("badge_id = ? AND user_id = ?", badge.ID, u.ID).Exist(new(UserBadge))
if err != nil {
return err
}
if exists {
return util.NewAlreadyExistErrorf("user badge already exists [user_id: %d, badge_id: %d]", u.ID, badge.ID)
}
if err := db.Insert(ctx, &UserBadge{
BadgeID: badge.ID,
UserID: u.ID,
}); err != nil {
exists, existErr := db.GetEngine(ctx).Where("badge_id = ? AND user_id = ?", badge.ID, u.ID).Exist(new(UserBadge))
if existErr == nil && exists {
return util.NewAlreadyExistErrorf("user badge already exists [user_id: %d, badge_id: %d]", u.ID, badge.ID)
}
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})
}
// 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 {
if len(badges) == 0 {
return nil
}
badgeSlugs := make([]string, 0, len(badges))
for _, badge := range badges {
badgeSlugs = append(badgeSlugs, badge.Slug)
}
var userBadges []UserBadge
if err := db.GetEngine(ctx).Table("user_badge").
Join("INNER", "badge", "badge.id = `user_badge`.badge_id").
Where("`user_badge`.user_id = ?", u.ID).In("`badge`.slug", badgeSlugs).
Find(&userBadges); err != nil {
return err
}
userBadgeIDs := make([]int64, 0, len(userBadges))
for _, ub := range userBadges {
userBadgeIDs = append(userBadgeIDs, ub.ID)
}
if len(userBadgeIDs) == 0 {
return nil
}
if _, err := db.GetEngine(ctx).Table("user_badge").In("id", userBadgeIDs).Delete(); err != nil {
return err
}
return nil
})
}
// SearchBadgeOptions represents the options when finding badges
type SearchBadgeOptions struct {
db.ListOptions
Keyword string
Slug string
ID int64
OrderBy db.SearchOrderBy
}
func (opts *SearchBadgeOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.Keyword != "" {
keywordCond := builder.Or(
db.BuildCaseInsensitiveLike("badge.slug", opts.Keyword),
db.BuildCaseInsensitiveLike("badge.description", opts.Keyword),
)
cond = cond.And(keywordCond)
}
if opts.ID > 0 {
cond = cond.And(builder.Eq{"badge.id": opts.ID})
}
if len(opts.Slug) > 0 {
cond = cond.And(builder.Eq{"badge.slug": opts.Slug})
}
return cond
}
func (opts *SearchBadgeOptions) ToOrders() string {
return opts.OrderBy.String()
}
// SearchBadges returns badges based on the provided SearchBadgeOptions options
func SearchBadges(ctx context.Context, opts *SearchBadgeOptions) ([]*Badge, int64, error) {
return db.FindAndCount[Badge](ctx, opts)
}