Update per feedback

pull/31262/head
techknowlogick 1 month ago
parent 9234ef5ecc
commit f601501fc1

@ -46,14 +46,25 @@ func GetUserBadges(ctx context.Context, u *User) ([]*Badge, int64, error) {
return badges, count, err
}
// GetBadgeUsers returns the users that have a specific badge.
func GetBadgeUsers(ctx context.Context, b *Badge) ([]*User, int64, error) {
// GetBadgeUsersOptions contains options for getting users with a specific badge
type GetBadgeUsersOptions struct {
db.ListOptions
Badge *Badge
}
// 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=?", b.Slug)
users := make([]*User, 0, 8)
Where("badge.slug=?", opts.Badge.Slug)
if opts.Page > 0 {
sess = db.SetSessionPagination(sess, opts)
}
users := make([]*User, 0, opts.PageSize)
count, err := sess.FindAndCount(&users)
return users, count, err
}
@ -82,11 +93,23 @@ func UpdateBadge(ctx context.Context, badge *Badge) error {
return err
}
// DeleteBadge deletes a badge.
// DeleteBadge deletes a badge and all associated user_badge entries.
func DeleteBadge(ctx context.Context, badge *Badge) error {
_, err := db.GetEngine(ctx).Where("slug=?", badge.Slug).Delete(badge)
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 = (SELECT id FROM badge WHERE slug = ?)", badge.Slug).
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 {
@ -123,19 +146,19 @@ func RemoveUserBadge(ctx context.Context, u *User, badge *Badge) error {
// 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 {
subQuery := builder.
Select("id").
From("badge").
Where(builder.Eq{"slug": badge.Slug})
slugs := make([]string, len(badges))
for i, badge := range badges {
slugs[i] = badge.Slug
}
if _, err := db.GetEngine(ctx).
Table("user_badge").
Join("INNER", "badge", "`user_badge`.badge_id = badge.id").
Where("`user_badge`.user_id = ?", u.ID).
And(builder.In("badge_id", subQuery)).
And(builder.In("badge.slug", slugs)).
Delete(&UserBadge{}); err != nil {
return err
}
}
return nil
})
}
@ -155,8 +178,6 @@ type SearchBadgeOptions struct {
ID int64
OrderBy db.SearchOrderBy
Actor *User // The user doing the search
ExtraParamStrings map[string]string
}
func (opts *SearchBadgeOptions) ToConds() builder.Cond {
@ -174,15 +195,6 @@ func (opts *SearchBadgeOptions) ToOrders() string {
return orderBy
}
func (opts *SearchBadgeOptions) ToJoins() []db.JoinFunc {
return []db.JoinFunc{
func(e db.Engine) error {
e.Join("INNER", "badge", "`user_badge`.badge_id=badge.id")
return nil
},
}
}
func SearchBadges(ctx context.Context, opts *SearchBadgeOptions) (badges []*Badge, _ int64, _ error) {
sessCount := opts.toSearchQueryBase(ctx)
count, err := sessCount.Count(new(Badge))
@ -233,3 +245,16 @@ func (opts *SearchBadgeOptions) toSearchQueryBase(ctx context.Context) *xorm.Ses
return e.Where(cond)
}
// GetBadgeByID returns a specific badge by ID
func GetBadgeByID(ctx context.Context, id int64) (*Badge, error) {
badge := new(Badge)
has, err := db.GetEngine(ctx).ID(id).Get(badge)
if err != nil {
return nil, err
}
if !has {
return nil, ErrBadgeNotExist{ID: id}
}
return badge, nil
}

@ -131,6 +131,14 @@ func (err ErrBadgeAlreadyExist) Unwrap() error {
// ErrBadgeNotExist represents a "BadgeNotExist" kind of error.
type ErrBadgeNotExist struct {
Slug string
ID int64
}
func (err ErrBadgeNotExist) Error() string {
if err.ID > 0 {
return fmt.Sprintf("badge does not exist [id: %d]", err.ID)
}
return fmt.Sprintf("badge does not exist [slug: %s]", err.Slug)
}
// IsErrBadgeNotExist checks if an error is a ErrBadgeNotExist.
@ -139,10 +147,6 @@ func IsErrBadgeNotExist(err error) bool {
return ok
}
func (err ErrBadgeNotExist) Error() string {
return fmt.Sprintf("badge does not exist [slug: %s]", err.Slug)
}
// Unwrap unwraps this error as a ErrNotExist error
func (err ErrBadgeNotExist) Unwrap() error {
return util.ErrNotExist

@ -7,14 +7,13 @@ import (
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/web/explore"
"code.gitea.io/gitea/services/context"
@ -23,11 +22,11 @@ import (
)
const (
tplBadges base.TplName = "admin/badge/list"
tplBadgeNew base.TplName = "admin/badge/new"
tplBadgeView base.TplName = "admin/badge/view"
tplBadgeEdit base.TplName = "admin/badge/edit"
tplBadgeUsers base.TplName = "admin/badge/users"
tplBadges templates.TplName = "admin/badge/list"
tplBadgeNew templates.TplName = "admin/badge/new"
tplBadgeView templates.TplName = "admin/badge/view"
tplBadgeEdit templates.TplName = "admin/badge/edit"
tplBadgeUsers templates.TplName = "admin/badge/users"
)
// BadgeSearchDefaultAdminSort is the default sort type for admin view
@ -97,14 +96,14 @@ func NewBadgePost(ctx *context.Context) {
log.Trace("Badge created by admin (%s): %s", ctx.Doer.Name, b.Slug)
ctx.Flash.Success(ctx.Tr("admin.badges.new_success", b.Slug))
ctx.Redirect(setting.AppSubURL + "/admin/badges/" + strconv.FormatInt(b.ID, 10))
ctx.Redirect(setting.AppSubURL + "/-/admin/badges/" + url.PathEscape(b.Slug))
}
func prepareBadgeInfo(ctx *context.Context) *user_model.Badge {
b, err := user_model.GetBadge(ctx, ctx.PathParam(":badge_slug"))
if err != nil {
if user_model.IsErrBadgeNotExist(err) {
ctx.Redirect(setting.AppSubURL + "/admin/badges")
ctx.Redirect(setting.AppSubURL + "/-/admin/badges")
} else {
ctx.ServerError("GetBadge", err)
}
@ -112,10 +111,16 @@ func prepareBadgeInfo(ctx *context.Context) *user_model.Badge {
}
ctx.Data["Badge"] = b
users, count, err := user_model.GetBadgeUsers(ctx, b)
opts := &user_model.GetBadgeUsersOptions{
ListOptions: db.ListOptions{
PageSize: setting.UI.User.RepoPagingNum,
},
Badge: b,
}
users, count, err := user_model.GetBadgeUsers(ctx, opts)
if err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.Redirect(setting.AppSubURL + "/admin/badges")
ctx.Redirect(setting.AppSubURL + "/-/admin/badges")
} else {
ctx.ServerError("GetBadgeUsers", err)
}
@ -187,7 +192,7 @@ func EditBadgePost(ctx *context.Context) {
log.Trace("Badge updated by admin (%s): %s", ctx.Doer.Name, b.Slug)
ctx.Flash.Success(ctx.Tr("admin.badges.update_success"))
ctx.Redirect(setting.AppSubURL + "/admin/badges/" + url.PathEscape(ctx.PathParam(":badge_slug")))
ctx.Redirect(setting.AppSubURL + "/-/admin/badges/" + url.PathEscape(ctx.PathParam(":badge_slug")))
}
// DeleteBadge response for deleting a badge
@ -206,20 +211,35 @@ func DeleteBadge(ctx *context.Context) {
log.Trace("Badge deleted by admin (%s): %s", ctx.Doer.Name, b.Slug)
ctx.Flash.Success(ctx.Tr("admin.badges.deletion_success"))
ctx.Redirect(setting.AppSubURL + "/admin/badges")
ctx.Redirect(setting.AppSubURL + "/-/admin/badges")
}
func BadgeUsers(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.badges.users_with_badge", ctx.PathParam(":badge_slug"))
ctx.Data["PageIsAdminBadges"] = true
users, _, err := user_model.GetBadgeUsers(ctx, &user_model.Badge{Slug: ctx.PathParam(":badge_slug")})
page := ctx.FormInt("page")
if page <= 0 {
page = 1
}
badge := &user_model.Badge{Slug: ctx.PathParam(":badge_slug")}
opts := &user_model.GetBadgeUsersOptions{
ListOptions: db.ListOptions{
Page: page,
PageSize: setting.UI.User.RepoPagingNum,
},
Badge: badge,
}
users, count, err := user_model.GetBadgeUsers(ctx, opts)
if err != nil {
ctx.ServerError("GetBadgeUsers", err)
return
}
ctx.Data["Users"] = users
ctx.Data["Total"] = count
ctx.Data["Page"] = context.NewPagination(int(count), setting.UI.User.RepoPagingNum, page, 5)
ctx.HTML(http.StatusOK, tplBadgeUsers)
}
@ -267,8 +287,41 @@ func DeleteBadgeUser(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("admin.badges.user_remove_success"))
} else {
ctx.Flash.Error("DeleteUser: " + err.Error())
}
ctx.JSONRedirect(fmt.Sprintf("%s/-/admin/badges/%s/users", setting.AppSubURL, ctx.PathParam(":badge_slug")))
}
// ViewBadgeUsers render badge's users page
func ViewBadgeUsers(ctx *context.Context) {
badge, err := user_model.GetBadge(ctx, ctx.PathParam(":slug"))
if err != nil {
ctx.ServerError("GetBadge", err)
return
}
ctx.JSONRedirect(fmt.Sprintf("%s/admin/badges/%s/users", setting.AppSubURL, ctx.PathParam(":badge_slug")))
page := ctx.FormInt("page")
if page <= 0 {
page = 1
}
opts := &user_model.GetBadgeUsersOptions{
ListOptions: db.ListOptions{
Page: page,
PageSize: setting.UI.User.RepoPagingNum,
},
Badge: badge,
}
users, count, err := user_model.GetBadgeUsers(ctx, opts)
if err != nil {
ctx.ServerError("GetBadgeUsers", err)
return
}
ctx.Data["Title"] = badge.Description
ctx.Data["Badge"] = badge
ctx.Data["Users"] = users
ctx.Data["Total"] = count
ctx.Data["Pages"] = context.NewPagination(int(count), setting.UI.User.RepoPagingNum, page, 5)
ctx.HTML(http.StatusOK, tplBadgeUsers)
}

@ -8,12 +8,12 @@ import (
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
)
func RenderBadgeSearch(ctx *context.Context, opts *user_model.SearchBadgeOptions, tplName base.TplName) {
func RenderBadgeSearch(ctx *context.Context, opts *user_model.SearchBadgeOptions, tplName templates.TplName) {
// Sitemap index for sitemap paths
opts.Page = int(ctx.PathParamInt64("idx"))
if opts.Page <= 1 {
@ -68,10 +68,7 @@ func RenderBadgeSearch(ctx *context.Context, opts *user_model.SearchBadgeOptions
ctx.Data["Badges"] = badges
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
pager.SetDefaultParams(ctx)
for paramKey, paramVal := range opts.ExtraParamStrings {
pager.AddParamString(paramKey, paramVal)
}
pager.AddParamFromRequest(ctx.Req)
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplName)

@ -44,3 +44,15 @@ func DeleteBadge(ctx context.Context, b *user_model.Badge) error {
return nil
}
// GetBadgeUsers returns the users that have a specific badge
func GetBadgeUsers(ctx context.Context, badge *user_model.Badge, page, pageSize int) ([]*user_model.User, int64, error) {
opts := &user_model.GetBadgeUsersOptions{
ListOptions: db.ListOptions{
Page: page,
PageSize: pageSize,
},
Badge: badge,
}
return user_model.GetBadgeUsers(ctx, opts)
}

@ -3,7 +3,7 @@
<h4 class="ui top attached header">
{{ctx.Locale.Tr "admin.badges.badges_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})
<div class="ui right">
<a class="ui primary tiny button" href="{{AppSubUrl}}/admin/badges/new">{{ctx.Locale.Tr "admin.badges.new_badge"}}</a>
<a class="ui primary tiny button" href="{{AppSubUrl}}/-/admin/badges/new">{{ctx.Locale.Tr "admin.badges.new_badge"}}</a>
</div>
</h4>
<div class="ui attached segment">

@ -26,6 +26,7 @@
</div>
</div>
{{end}}
{{template "base/paginate" .}}
<div class="ui bottom attached segment">
<form class="ui form" id="search-badge-user-form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}

Loading…
Cancel
Save