github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/service/project.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "net/http" 7 8 "github.com/evergreen-ci/evergreen/alerts" 9 "github.com/evergreen-ci/evergreen/model" 10 "github.com/evergreen-ci/evergreen/model/user" 11 "github.com/evergreen-ci/evergreen/util" 12 "github.com/gorilla/mux" 13 "github.com/pkg/errors" 14 "gopkg.in/mgo.v2/bson" 15 ) 16 17 // publicProjectFields are the fields needed by the UI 18 // on base_angular and the menu 19 type UIProjectFields struct { 20 Identifier string `json:"identifier"` 21 DisplayName string `json:"display_name"` 22 Repo string `json:"repo_name"` 23 Owner string `json:"owner_name"` 24 } 25 26 // filterAuthorizedProjects iterates through a list of projects and returns a list of all the projects that a user 27 // is authorized to view and edit the settings of. 28 func (uis *UIServer) filterAuthorizedProjects(u *user.DBUser) ([]model.ProjectRef, error) { 29 allProjects, err := model.FindAllProjectRefs() 30 if err != nil { 31 return nil, err 32 } 33 authorizedProjects := []model.ProjectRef{} 34 // only returns projects for which the user is authorized to see. 35 for _, project := range allProjects { 36 if uis.isSuperUser(u) || isAdmin(u, &project) { 37 authorizedProjects = append(authorizedProjects, project) 38 } 39 } 40 return authorizedProjects, nil 41 42 } 43 func (uis *UIServer) projectsPage(w http.ResponseWriter, r *http.Request) { 44 dbUser := MustHaveUser(r) 45 projCtx := MustHaveProjectContext(r) 46 47 allProjects, err := uis.filterAuthorizedProjects(dbUser) 48 if err != nil { 49 uis.LoggedError(w, r, http.StatusInternalServerError, err) 50 return 51 } 52 53 // construct a json-marshaling friendly representation of our supported triggers 54 allTaskTriggers := []interface{}{} 55 for _, taskTrigger := range alerts.AvailableTaskFailTriggers { 56 allTaskTriggers = append(allTaskTriggers, struct { 57 Id string `json:"id"` 58 Display string `json:"display"` 59 }{taskTrigger.Id(), taskTrigger.Display()}) 60 } 61 62 data := struct { 63 ProjectData projectContext 64 User *user.DBUser 65 AllProjects []model.ProjectRef 66 AvailableTriggers []interface{} 67 }{projCtx, GetUser(r), allProjects, allTaskTriggers} 68 69 uis.WriteHTML(w, http.StatusOK, data, "base", "projects.html", "base_angular.html", "menu.html") 70 } 71 72 func (uis *UIServer) projectPage(w http.ResponseWriter, r *http.Request) { 73 74 _ = MustHaveProjectContext(r) 75 _ = MustHaveUser(r) 76 77 vars := mux.Vars(r) 78 id := vars["project_id"] 79 80 projRef, err := model.FindOneProjectRef(id) 81 82 if err != nil { 83 uis.LoggedError(w, r, http.StatusInternalServerError, err) 84 return 85 } 86 projVars, err := model.FindOneProjectVars(id) 87 88 if err != nil { 89 uis.LoggedError(w, r, http.StatusInternalServerError, err) 90 return 91 } 92 93 projVars.RedactPrivateVars() 94 95 data := struct { 96 ProjectRef *model.ProjectRef 97 ProjectVars *model.ProjectVars 98 }{projRef, projVars} 99 100 // the project context has all projects so make the ui list using all projects 101 uis.WriteJSON(w, http.StatusOK, data) 102 } 103 104 // ProjectNotFound calls WriteHTML with the invalid-project page. It should be called whenever the 105 // project specified by the user does not exist, or when there are no projects at all. 106 func (uis *UIServer) ProjectNotFound(projCtx projectContext, w http.ResponseWriter, r *http.Request) { 107 uis.WriteHTML(w, http.StatusNotFound, struct { 108 ProjectData projectContext 109 User *user.DBUser 110 }{projCtx, GetUser(r)}, "base", "invalid_project.html", "base_angular.html", "menu.html") 111 } 112 113 func (uis *UIServer) modifyProject(w http.ResponseWriter, r *http.Request) { 114 115 dbUser := MustHaveUser(r) 116 _ = MustHaveProjectContext(r) 117 118 vars := mux.Vars(r) 119 id := vars["project_id"] 120 121 projectRef, err := model.FindOneProjectRef(id) 122 123 if err != nil { 124 uis.LoggedError(w, r, http.StatusInternalServerError, err) 125 return 126 } 127 128 if projectRef == nil { 129 http.Error(w, "Project not found", http.StatusNotFound) 130 return 131 } 132 133 responseRef := struct { 134 Identifier string `json:"id"` 135 DisplayName string `json:"display_name"` 136 RemotePath string `json:"remote_path"` 137 BatchTime int `json:"batch_time"` 138 DeactivatePrevious bool `json:"deactivate_previous"` 139 Branch string `json:"branch_name"` 140 ProjVarsMap map[string]string `json:"project_vars"` 141 PrivateVars map[string]bool `json:"private_vars"` 142 Enabled bool `json:"enabled"` 143 Private bool `json:"private"` 144 Owner string `json:"owner_name"` 145 Repo string `json:"repo_name"` 146 Admins []string `json:"admins"` 147 AlertConfig map[string][]struct { 148 Provider string `json:"provider"` 149 Settings map[string]interface{} `json:"settings"` 150 } `json:"alert_config"` 151 }{} 152 153 if err = util.ReadJSONInto(util.NewRequestReader(r), &responseRef); err != nil { 154 http.Error(w, fmt.Sprintf("Error parsing request body %v", err), http.StatusInternalServerError) 155 return 156 } 157 158 projectRef.DisplayName = responseRef.DisplayName 159 projectRef.RemotePath = responseRef.RemotePath 160 projectRef.BatchTime = responseRef.BatchTime 161 projectRef.Branch = responseRef.Branch 162 projectRef.Enabled = responseRef.Enabled 163 projectRef.Private = responseRef.Private 164 projectRef.Owner = responseRef.Owner 165 projectRef.DeactivatePrevious = responseRef.DeactivatePrevious 166 projectRef.Repo = responseRef.Repo 167 projectRef.Admins = responseRef.Admins 168 projectRef.Identifier = id 169 170 projectRef.Alerts = map[string][]model.AlertConfig{} 171 for triggerId, alerts := range responseRef.AlertConfig { 172 //TODO validate the triggerID, provider, and settings. 173 for _, alert := range alerts { 174 projectRef.Alerts[triggerId] = append(projectRef.Alerts[triggerId], model.AlertConfig{ 175 Provider: alert.Provider, 176 Settings: bson.M(alert.Settings), 177 }) 178 } 179 } 180 181 err = projectRef.Upsert() 182 183 if err != nil { 184 uis.LoggedError(w, r, http.StatusInternalServerError, err) 185 return 186 } 187 188 //modify project vars if necessary 189 projectVars := model.ProjectVars{id, responseRef.ProjVarsMap, responseRef.PrivateVars} 190 _, err = projectVars.Upsert() 191 192 if err != nil { 193 uis.LoggedError(w, r, http.StatusInternalServerError, err) 194 return 195 } 196 197 allProjects, err := uis.filterAuthorizedProjects(dbUser) 198 if err != nil { 199 uis.LoggedError(w, r, http.StatusInternalServerError, err) 200 return 201 } 202 data := struct { 203 AllProjects []model.ProjectRef 204 }{allProjects} 205 206 uis.WriteJSON(w, http.StatusOK, data) 207 } 208 209 func (uis *UIServer) addProject(w http.ResponseWriter, r *http.Request) { 210 211 dbUser := MustHaveUser(r) 212 _ = MustHaveProjectContext(r) 213 214 vars := mux.Vars(r) 215 id := vars["project_id"] 216 217 projectRef, err := model.FindOneProjectRef(id) 218 if err != nil { 219 uis.LoggedError(w, r, http.StatusInternalServerError, err) 220 return 221 } 222 if projectRef != nil { 223 http.Error(w, "Project already exists", http.StatusInternalServerError) 224 return 225 } 226 227 newProject := model.ProjectRef{ 228 Identifier: id, 229 Enabled: true, 230 Tracked: true, 231 RepoKind: "github", 232 } 233 234 err = newProject.Insert() 235 if err != nil { 236 uis.LoggedError(w, r, http.StatusInternalServerError, err) 237 return 238 } 239 240 allProjects, err := uis.filterAuthorizedProjects(dbUser) 241 242 if err != nil { 243 uis.LoggedError(w, r, http.StatusInternalServerError, err) 244 return 245 } 246 247 data := struct { 248 Available bool 249 ProjectId string 250 AllProjects []model.ProjectRef 251 }{true, id, allProjects} 252 253 uis.WriteJSON(w, http.StatusOK, data) 254 } 255 256 // setRevision sets the latest revision in the Repository 257 // database to the revision sent from the projects page. 258 func (uis *UIServer) setRevision(w http.ResponseWriter, r *http.Request) { 259 MustHaveUser(r) 260 261 vars := mux.Vars(r) 262 id := vars["project_id"] 263 264 body := util.NewRequestReader(r) 265 defer body.Close() 266 267 data, err := ioutil.ReadAll(body) 268 if err != nil { 269 uis.LoggedError(w, r, http.StatusNotFound, err) 270 return 271 } 272 273 revision := string(data) 274 if revision == "" { 275 uis.LoggedError(w, r, http.StatusBadRequest, errors.Errorf("revision sent was empty")) 276 return 277 } 278 279 // update the latest revision to be the revision id 280 err = model.UpdateLastRevision(id, revision) 281 if err != nil { 282 uis.LoggedError(w, r, http.StatusInternalServerError, err) 283 return 284 } 285 286 // update the projectRef too 287 projectRef, err := model.FindOneProjectRef(id) 288 if err != nil { 289 uis.LoggedError(w, r, http.StatusInternalServerError, err) 290 return 291 } 292 projectRef.RepotrackerError.Exists = false 293 projectRef.RepotrackerError.InvalidRevision = "" 294 projectRef.RepotrackerError.MergeBaseRevision = "" 295 err = projectRef.Upsert() 296 if err != nil { 297 uis.LoggedError(w, r, http.StatusInternalServerError, err) 298 return 299 } 300 301 uis.WriteJSON(w, http.StatusOK, nil) 302 }