mirror of
https://github.com/go-gitea/gitea.git
synced 2026-04-09 04:25:50 +02:00
* 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)
200 lines
5.9 KiB
Go
200 lines
5.9 KiB
Go
package group
|
|
|
|
import (
|
|
"context"
|
|
"slices"
|
|
|
|
"code.gitea.io/gitea/models/git"
|
|
group_model "code.gitea.io/gitea/models/group"
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
"code.gitea.io/gitea/models/unit"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/structs"
|
|
"code.gitea.io/gitea/modules/translation"
|
|
"code.gitea.io/gitea/services/convert"
|
|
repo_service "code.gitea.io/gitea/services/repository"
|
|
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
|
|
)
|
|
|
|
type WebSearchGroup struct {
|
|
Group *structs.Group `json:"group,omitempty"`
|
|
LatestCommitStatus *git.CommitStatus `json:"latest_commit_status"`
|
|
LocaleLatestCommitStatus string `json:"locale_latest_commit_status"`
|
|
Subgroups []*WebSearchGroup `json:"subgroups"`
|
|
Repos []*repo_service.WebSearchRepository `json:"repos"`
|
|
}
|
|
|
|
type GroupWebSearchResult struct {
|
|
OK bool `json:"ok"`
|
|
Data *WebSearchGroup `json:"data"`
|
|
}
|
|
|
|
type GroupWebSearchOptions struct {
|
|
Ctx context.Context
|
|
Locale translation.Locale
|
|
Recurse bool
|
|
Actor *user_model.User
|
|
RepoOpts *repo_model.SearchRepoOptions
|
|
GroupOpts *group_model.FindGroupsOptions
|
|
OrgID int64
|
|
}
|
|
|
|
// results for root-level queries //
|
|
|
|
type WebSearchGroupRoot struct {
|
|
Groups []*WebSearchGroup
|
|
Repos []*repo_service.WebSearchRepository
|
|
}
|
|
|
|
type GroupWebSearchRootResult struct {
|
|
OK bool `json:"ok"`
|
|
Data *WebSearchGroupRoot `json:"data"`
|
|
}
|
|
|
|
func ToWebSearchRepo(ctx context.Context, repo *repo_model.Repository) *repo_service.WebSearchRepository {
|
|
return &repo_service.WebSearchRepository{
|
|
Repository: &structs.Repository{
|
|
ID: repo.ID,
|
|
FullName: repo.FullName(),
|
|
Fork: repo.IsFork,
|
|
Private: repo.IsPrivate,
|
|
Template: repo.IsTemplate,
|
|
Mirror: repo.IsMirror,
|
|
Stars: repo.NumStars,
|
|
HTMLURL: repo.HTMLURL(ctx),
|
|
Link: repo.Link(),
|
|
Internal: !repo.IsPrivate && repo.Owner.Visibility == structs.VisibleTypePrivate,
|
|
GroupSortOrder: repo.GroupSortOrder,
|
|
GroupID: repo.GroupID,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (w *WebSearchGroup) doLoadChildren(opts *GroupWebSearchOptions) error {
|
|
opts.RepoOpts.OwnerID = opts.OrgID
|
|
opts.RepoOpts.GroupID = 0
|
|
opts.GroupOpts.OwnerID = opts.OrgID
|
|
opts.GroupOpts.ParentGroupID = 0
|
|
|
|
if w.Group != nil {
|
|
opts.RepoOpts.GroupID = w.Group.ID
|
|
opts.RepoOpts.ListAll = true
|
|
opts.GroupOpts.ParentGroupID = w.Group.ID
|
|
opts.GroupOpts.ListAll = true
|
|
}
|
|
repos, _, err := repo_model.SearchRepository(opts.Ctx, opts.RepoOpts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
slices.SortStableFunc(repos, func(a, b *repo_model.Repository) int {
|
|
return a.GroupSortOrder - b.GroupSortOrder
|
|
})
|
|
latestCommitStatuses, err := commitstatus_service.FindReposLastestCommitStatuses(opts.Ctx, repos)
|
|
if err != nil {
|
|
log.Error("FindReposLastestCommitStatuses: %v", err)
|
|
return err
|
|
}
|
|
latestIdx := -1
|
|
for i, r := range repos {
|
|
wsr := ToWebSearchRepo(opts.Ctx, r)
|
|
if latestCommitStatuses[i] != nil {
|
|
wsr.LatestCommitStatus = latestCommitStatuses[i]
|
|
wsr.LocaleLatestCommitStatus = latestCommitStatuses[i].LocaleString(opts.Locale)
|
|
if latestIdx > -1 {
|
|
if latestCommitStatuses[i].UpdatedUnix.AsLocalTime().Unix() > int64(latestCommitStatuses[latestIdx].UpdatedUnix.AsLocalTime().Unix()) {
|
|
latestIdx = i
|
|
}
|
|
} else {
|
|
latestIdx = i
|
|
}
|
|
}
|
|
w.Repos = append(w.Repos, wsr)
|
|
}
|
|
if w.Group != nil && latestIdx > -1 {
|
|
w.LatestCommitStatus = latestCommitStatuses[latestIdx]
|
|
}
|
|
w.Subgroups = make([]*WebSearchGroup, 0)
|
|
groups, err := group_model.FindGroupsByCond(opts.Ctx, opts.GroupOpts, group_model.AccessibleGroupCondition(opts.Actor, unit.TypeInvalid))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, g := range groups {
|
|
toAppend, err := ToWebSearchGroup(g, opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
w.Subgroups = append(w.Subgroups, toAppend)
|
|
}
|
|
|
|
if opts.Recurse {
|
|
for _, sg := range w.Subgroups {
|
|
err = sg.doLoadChildren(opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ToWebSearchGroup(group *group_model.Group, opts *GroupWebSearchOptions) (*WebSearchGroup, error) {
|
|
res := new(WebSearchGroup)
|
|
|
|
res.Repos = make([]*repo_service.WebSearchRepository, 0)
|
|
res.Subgroups = make([]*WebSearchGroup, 0)
|
|
var err error
|
|
if group != nil {
|
|
if res.Group, err = convert.ToAPIGroup(opts.Ctx, group, opts.Actor); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func SearchRepoGroupWeb(group *group_model.Group, opts *GroupWebSearchOptions) (*GroupWebSearchResult, error) {
|
|
res := new(WebSearchGroup)
|
|
var err error
|
|
res, err = ToWebSearchGroup(group, opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = res.doLoadChildren(opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &GroupWebSearchResult{
|
|
Data: res,
|
|
OK: true,
|
|
}, nil
|
|
}
|
|
|
|
/* func SearchRootItems(ctx context.Context, oid int64, groupSearchOptions *group_model.FindGroupsOptions, repoSearchOptions *repo_model.SearchRepoOptions, actor *user_model.User, recursive bool) (*WebSearchGroupRoot, error) {
|
|
root := &WebSearchGroupRoot{
|
|
Repos: make([]*repo_service.WebSearchRepository, 0),
|
|
Groups: make([]*WebSearchGroup, 0),
|
|
}
|
|
groupSearchOptions.ParentGroupID = 0
|
|
groups, err := group_model.FindGroupsByCond(ctx, groupSearchOptions, group_model.AccessibleGroupCondition(actor, unit.TypeInvalid))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, g := range groups {
|
|
toAppend, err := ToWebSearchGroup(ctx, g, actor, oid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
root.Groups = append(root.Groups, toAppend)
|
|
}
|
|
repos, _, err := repo_model.SearchRepositoryByCondition(ctx, repoSearchOptions, repo_model.AccessibleRepositoryCondition(actor, unit.TypeInvalid), true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, r := range repos {
|
|
root.Repos = append(root.Repos, ToWebSearchRepo(ctx, r))
|
|
}
|
|
|
|
return root, nil
|
|
}
|
|
*/
|