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  }