mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-30 20:53:54 +02:00
changes
* move error-related code for groups to its own file * update group avatar logic remove unused/duplicate logic * update `FindGroupsOptions.ToConds()` allow passing `-1` as the `ParentGroupID`, meaning "find matching groups regardless of the parent group id" * add `DedupeBy` function to container module this removes duplicate items from a slice using a custom function * add `SliceMap` util works like javascripts's `Array.prototoype.map`, taking in a slice and transforming each element with the provided function * add group service functions included so far: - avatar uploading/deletion - group deletion - group creation - group moving (including moving item inside a group) - group update - team management - add team - remove team - update team permissions - recalculating team access (in event of group move) - group searching (only used in frontend/web components for now)
This commit is contained in:
+5
-49
@@ -1,66 +1,22 @@
|
||||
package group
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models/avatars"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/avatar"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"context"
|
||||
"fmt"
|
||||
"image/png"
|
||||
"io"
|
||||
"net/url"
|
||||
|
||||
"code.gitea.io/gitea/models/avatars"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
func (g *Group) CustomAvatarRelativePath() string {
|
||||
return g.Avatar
|
||||
}
|
||||
func generateRandomAvatar(ctx context.Context, group *Group) error {
|
||||
idToString := fmt.Sprintf("%d", group.ID)
|
||||
|
||||
seed := idToString
|
||||
img, err := avatar.RandomImage([]byte(seed))
|
||||
if err != nil {
|
||||
return fmt.Errorf("RandomImage: %w", err)
|
||||
}
|
||||
|
||||
group.Avatar = idToString
|
||||
|
||||
if err = storage.SaveFrom(storage.RepoAvatars, group.CustomAvatarRelativePath(), func(w io.Writer) error {
|
||||
if err = png.Encode(w, img); err != nil {
|
||||
log.Error("Encode: %v", err)
|
||||
}
|
||||
return err
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Failed to create dir %s: %w", group.CustomAvatarRelativePath(), err)
|
||||
}
|
||||
|
||||
log.Info("New random avatar created for repository: %d", group.ID)
|
||||
|
||||
if _, err = db.GetEngine(ctx).ID(group.ID).Cols("avatar").NoAutoTime().Update(group); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (g *Group) relAvatarLink(ctx context.Context) string {
|
||||
// If no avatar - path is empty
|
||||
avatarPath := g.CustomAvatarRelativePath()
|
||||
if len(avatarPath) == 0 {
|
||||
switch mode := setting.RepoAvatar.Fallback; mode {
|
||||
case "image":
|
||||
return setting.RepoAvatar.FallbackImage
|
||||
case "random":
|
||||
if err := generateRandomAvatar(ctx, g); err != nil {
|
||||
log.Error("generateRandomAvatar: %v", err)
|
||||
}
|
||||
default:
|
||||
// default behaviour: do not display avatar
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return setting.AppSubURL + "/group-avatars/" + url.PathEscape(g.Avatar)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package group
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
type ErrGroupNotExist struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
// IsErrGroupNotExist checks if an error is a ErrCommentNotExist.
|
||||
func IsErrGroupNotExist(err error) bool {
|
||||
var errGroupNotExist ErrGroupNotExist
|
||||
ok := errors.As(err, &errGroupNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrGroupNotExist) Error() string {
|
||||
return fmt.Sprintf("group does not exist [id: %d]", err.ID)
|
||||
}
|
||||
|
||||
func (err ErrGroupNotExist) Unwrap() error {
|
||||
return util.ErrNotExist
|
||||
}
|
||||
|
||||
type ErrGroupTooDeep struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
func IsErrGroupTooDeep(err error) bool {
|
||||
var errGroupTooDeep ErrGroupTooDeep
|
||||
ok := errors.As(err, &errGroupTooDeep)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrGroupTooDeep) Error() string {
|
||||
return fmt.Sprintf("group has reached or exceeded the subgroup nesting limit [id: %d]", err.ID)
|
||||
}
|
||||
+54
-41
@@ -136,10 +136,21 @@ func (opts FindGroupsOptions) ToConds() builder.Cond {
|
||||
if opts.OwnerID != 0 {
|
||||
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||
}
|
||||
if opts.ParentGroupID != 0 {
|
||||
if opts.ParentGroupID > 0 {
|
||||
cond = cond.And(builder.Eq{"parent_group_id": opts.ParentGroupID})
|
||||
} else {
|
||||
cond = cond.And(builder.IsNull{"parent_group_id"})
|
||||
} else if opts.ParentGroupID == 0 {
|
||||
cond = cond.And(builder.Eq{"parent_group_id": 0})
|
||||
}
|
||||
if opts.CanCreateIn.Has() && opts.ActorID > 0 {
|
||||
cond = cond.And(builder.In("id",
|
||||
builder.Select("group_team.group_id").
|
||||
From("group_team").
|
||||
Where(builder.Eq{"team_user.uid": opts.ActorID}).
|
||||
Join("INNER", "team_user", "team_user.team_id = group_team.team_id").
|
||||
And(builder.Eq{"group_team.can_create_in": true})))
|
||||
}
|
||||
if opts.Name != "" {
|
||||
cond = cond.And(builder.Eq{"lower_name": opts.Name})
|
||||
}
|
||||
return cond
|
||||
}
|
||||
@@ -186,53 +197,55 @@ func GetParentGroupChain(ctx context.Context, groupID int64) (GroupList, error)
|
||||
groupList = append(groupList, currentGroup)
|
||||
currentGroupID = currentGroup.ParentGroupID
|
||||
}
|
||||
slices.Reverse(groupList)
|
||||
return groupList, nil
|
||||
}
|
||||
|
||||
func GetParentGroupIDChain(ctx context.Context, groupID int64) (ids []int64, err error) {
|
||||
groupList, err := GetParentGroupChain(ctx, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ids = util.SliceMap(groupList, func(g *Group) int64 {
|
||||
return g.ID
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// ParentGroupCond returns a condition matching a group and its ancestors
|
||||
func ParentGroupCond(idStr string, groupID int64) builder.Cond {
|
||||
groupList, err := GetParentGroupChain(db.DefaultContext, groupID)
|
||||
groupList, err := GetParentGroupIDChain(db.DefaultContext, groupID)
|
||||
if err != nil {
|
||||
log.Info("Error building group cond: %w", err)
|
||||
return builder.NotIn(idStr)
|
||||
}
|
||||
return builder.In(
|
||||
idStr,
|
||||
util.SliceMap[*Group, int64](groupList, func(it *Group) int64 {
|
||||
return it.ID
|
||||
}),
|
||||
)
|
||||
return builder.In(idStr, groupList)
|
||||
}
|
||||
|
||||
type ErrGroupNotExist struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
// IsErrGroupNotExist checks if an error is a ErrCommentNotExist.
|
||||
func IsErrGroupNotExist(err error) bool {
|
||||
var errGroupNotExist ErrGroupNotExist
|
||||
ok := errors.As(err, &errGroupNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrGroupNotExist) Error() string {
|
||||
return fmt.Sprintf("group does not exist [id: %d]", err.ID)
|
||||
}
|
||||
|
||||
func (err ErrGroupNotExist) Unwrap() error {
|
||||
return util.ErrNotExist
|
||||
}
|
||||
|
||||
type ErrGroupTooDeep struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
func IsErrGroupTooDeep(err error) bool {
|
||||
var errGroupTooDeep ErrGroupTooDeep
|
||||
ok := errors.As(err, &errGroupTooDeep)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrGroupTooDeep) Error() string {
|
||||
return fmt.Sprintf("group has reached or exceeded the subgroup nesting limit [id: %d]", err.ID)
|
||||
func MoveGroup(ctx context.Context, group *Group, newParent int64, newSortOrder int) error {
|
||||
sess := db.GetEngine(ctx)
|
||||
ng, err := GetGroupByID(ctx, newParent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ng.OwnerID != group.OwnerID {
|
||||
return fmt.Errorf("group[%d]'s ownerID is not equal to new paretn group[%d]'s owner ID", group.ID, ng.ID)
|
||||
}
|
||||
group.ParentGroupID = newParent
|
||||
group.SortOrder = newSortOrder
|
||||
if _, err = sess.Table(group.TableName()).
|
||||
Where("id = ?", group.ID).
|
||||
MustCols("parent_group_id").
|
||||
Update(group, &Group{
|
||||
ID: group.ID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if group.ParentGroup != nil && newParent != 0 {
|
||||
group.ParentGroup = nil
|
||||
if err = group.LoadParentGroup(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user