code.gitea.io/gitea@v1.22.3/models/activities/action_list.go (about) 1 // Copyright 2018 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package activities 5 6 import ( 7 "context" 8 "fmt" 9 "strconv" 10 11 "code.gitea.io/gitea/models/db" 12 issues_model "code.gitea.io/gitea/models/issues" 13 repo_model "code.gitea.io/gitea/models/repo" 14 user_model "code.gitea.io/gitea/models/user" 15 "code.gitea.io/gitea/modules/container" 16 "code.gitea.io/gitea/modules/util" 17 18 "xorm.io/builder" 19 ) 20 21 // ActionList defines a list of actions 22 type ActionList []*Action 23 24 func (actions ActionList) getUserIDs() []int64 { 25 return container.FilterSlice(actions, func(action *Action) (int64, bool) { 26 return action.ActUserID, true 27 }) 28 } 29 30 func (actions ActionList) LoadActUsers(ctx context.Context) (map[int64]*user_model.User, error) { 31 if len(actions) == 0 { 32 return nil, nil 33 } 34 35 userIDs := actions.getUserIDs() 36 userMaps := make(map[int64]*user_model.User, len(userIDs)) 37 err := db.GetEngine(ctx). 38 In("id", userIDs). 39 Find(&userMaps) 40 if err != nil { 41 return nil, fmt.Errorf("find user: %w", err) 42 } 43 44 for _, action := range actions { 45 action.ActUser = userMaps[action.ActUserID] 46 } 47 return userMaps, nil 48 } 49 50 func (actions ActionList) getRepoIDs() []int64 { 51 return container.FilterSlice(actions, func(action *Action) (int64, bool) { 52 return action.RepoID, true 53 }) 54 } 55 56 func (actions ActionList) LoadRepositories(ctx context.Context) error { 57 if len(actions) == 0 { 58 return nil 59 } 60 61 repoIDs := actions.getRepoIDs() 62 repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs)) 63 err := db.GetEngine(ctx).In("id", repoIDs).Find(&repoMaps) 64 if err != nil { 65 return fmt.Errorf("find repository: %w", err) 66 } 67 for _, action := range actions { 68 action.Repo = repoMaps[action.RepoID] 69 } 70 repos := repo_model.RepositoryList(util.ValuesOfMap(repoMaps)) 71 return repos.LoadUnits(ctx) 72 } 73 74 func (actions ActionList) loadRepoOwner(ctx context.Context, userMap map[int64]*user_model.User) (err error) { 75 if userMap == nil { 76 userMap = make(map[int64]*user_model.User) 77 } 78 79 missingUserIDs := container.FilterSlice(actions, func(action *Action) (int64, bool) { 80 if action.Repo == nil { 81 return 0, false 82 } 83 _, alreadyLoaded := userMap[action.Repo.OwnerID] 84 return action.Repo.OwnerID, !alreadyLoaded 85 }) 86 if len(missingUserIDs) == 0 { 87 return nil 88 } 89 90 if err := db.GetEngine(ctx). 91 In("id", missingUserIDs). 92 Find(&userMap); err != nil { 93 return fmt.Errorf("find user: %w", err) 94 } 95 96 for _, action := range actions { 97 if action.Repo != nil { 98 action.Repo.Owner = userMap[action.Repo.OwnerID] 99 } 100 } 101 102 return nil 103 } 104 105 // LoadAttributes loads all attributes 106 func (actions ActionList) LoadAttributes(ctx context.Context) error { 107 // the load sequence cannot be changed because of the dependencies 108 userMap, err := actions.LoadActUsers(ctx) 109 if err != nil { 110 return err 111 } 112 if err := actions.LoadRepositories(ctx); err != nil { 113 return err 114 } 115 if err := actions.loadRepoOwner(ctx, userMap); err != nil { 116 return err 117 } 118 if err := actions.LoadIssues(ctx); err != nil { 119 return err 120 } 121 return actions.LoadComments(ctx) 122 } 123 124 func (actions ActionList) LoadComments(ctx context.Context) error { 125 if len(actions) == 0 { 126 return nil 127 } 128 129 commentIDs := make([]int64, 0, len(actions)) 130 for _, action := range actions { 131 if action.CommentID > 0 { 132 commentIDs = append(commentIDs, action.CommentID) 133 } 134 } 135 if len(commentIDs) == 0 { 136 return nil 137 } 138 139 commentsMap := make(map[int64]*issues_model.Comment, len(commentIDs)) 140 if err := db.GetEngine(ctx).In("id", commentIDs).Find(&commentsMap); err != nil { 141 return fmt.Errorf("find comment: %w", err) 142 } 143 144 for _, action := range actions { 145 if action.CommentID > 0 { 146 action.Comment = commentsMap[action.CommentID] 147 if action.Comment != nil { 148 action.Comment.Issue = action.Issue 149 } 150 } 151 } 152 return nil 153 } 154 155 func (actions ActionList) LoadIssues(ctx context.Context) error { 156 if len(actions) == 0 { 157 return nil 158 } 159 160 conditions := builder.NewCond() 161 issueNum := 0 162 for _, action := range actions { 163 if action.IsIssueEvent() { 164 infos := action.GetIssueInfos() 165 if len(infos) == 0 { 166 continue 167 } 168 index, _ := strconv.ParseInt(infos[0], 10, 64) 169 if index > 0 { 170 conditions = conditions.Or(builder.Eq{ 171 "repo_id": action.RepoID, 172 "`index`": index, 173 }) 174 issueNum++ 175 } 176 } 177 } 178 if !conditions.IsValid() { 179 return nil 180 } 181 182 issuesMap := make(map[string]*issues_model.Issue, issueNum) 183 issues := make([]*issues_model.Issue, 0, issueNum) 184 if err := db.GetEngine(ctx).Where(conditions).Find(&issues); err != nil { 185 return fmt.Errorf("find issue: %w", err) 186 } 187 for _, issue := range issues { 188 issuesMap[fmt.Sprintf("%d-%d", issue.RepoID, issue.Index)] = issue 189 } 190 191 for _, action := range actions { 192 if !action.IsIssueEvent() { 193 continue 194 } 195 if index := action.getIssueIndex(); index > 0 { 196 if issue, ok := issuesMap[fmt.Sprintf("%d-%d", action.RepoID, index)]; ok { 197 action.Issue = issue 198 action.Issue.Repo = action.Repo 199 } 200 } 201 } 202 return nil 203 }