prow/prstatus/prstatus.go
func (da *DashboardAgent) HandlePrStatus(queryHandler PullRequestQueryHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		serverError := func(action string, err error) {
			da.log.WithError(err).Errorf("Error %s.", action)
			msg := fmt.Sprintf("500 Internal server error %s: %v", action, err)
			http.Error(w, msg, http.StatusInternalServerError)
		}

		data := UserData{
			Login: false,
		}

		// Get existing session. Invalidate everything if we fail and continue as
		// if not logged in.
		session, err := da.goac.CookieStore.Get(r, tokenSession)
		if err != nil {
			da.log.WithError(err).Info("Failed to get existing session, invalidating GitHub login session")
			if err := invalidateGitHubSession(w, r, session); err != nil {
				serverError("Failed to invalidate GitHub session", err)
				return
			}
		}

		// If access token exists, get user login using the access token. This is a
		// chance to validate whether the access token is consumable or not. If
		// not, we invalidate the sessions and continue as if not logged in.
		token, ok := session.Values[tokenKey].(*oauth2.Token)
		var user *github.User
		var botName string
		if ok && token.Valid() {
			githubClient := github.NewClient(func() []byte { return []byte(token.AccessToken) }, github.DefaultGraphQLEndpoint, github.DefaultAPIEndpoint)
			var err error
			botName, err = githubClient.BotName()
			user = &github.User{Login: botName}
			if err != nil {
				if strings.Contains(err.Error(), "401") {
					da.log.Info("Failed to access GitHub with existing access token, invalidating GitHub login session")
					if err := invalidateGitHubSession(w, r, session); err != nil {
						serverError("Failed to invalidate GitHub session", err)
						return
					}
				} else {
					serverError("Error with getting user login", err)
					return
				}
			}
		}

		if user != nil {
			login := user.Login
			data.Login = true
			// Saves login. We save the login under 2 cookies. One for the use of client to render the
			// data and one encoded for server to verify the identity of the authenticated user.
			http.SetCookie(w, &http.Cookie{
				Name:    loginSession,
				Value:   login,
				Path:    "/",
				Expires: time.Now().Add(time.Hour * 24 * 30),
				Secure:  true,
			})
			session.Values[loginKey] = login
			if err := session.Save(r, w); err != nil {
				serverError("Save oauth session", err)
				return
			}

			// Construct query
			ghc := github.NewClient(func() []byte { return []byte(token.AccessToken) }, github.DefaultGraphQLEndpoint, github.DefaultAPIEndpoint)
			query := da.ConstructSearchQuery(login)
			if err := r.ParseForm(); err == nil {
				if q := r.Form.Get("query"); q != "" {
					query = q
				}
			}
			// If neither repo nor org is specified in the search query. We limit the search to repos that
			// are configured with either Prow or Tide.
			if !queryConstrainsRepos(query) {
				for _, v := range da.repos {
					query += fmt.Sprintf(" repo:\"%s\"", v)
				}
			}
			pullRequests, err := queryHandler.QueryPullRequests(context.Background(), ghc, query)
			if err != nil {
				serverError("Error with querying user data.", err)
				return
			}
			var pullRequestWithContexts []PullRequestWithContexts
			for _, pr := range pullRequests {
				prcontexts, err := queryHandler.GetHeadContexts(ghc, pr)
				if err != nil {
					serverError("Error with getting head context of pr", err)
					continue
				}
				pullRequestWithContexts = append(pullRequestWithContexts, PullRequestWithContexts{
					Contexts:    prcontexts,
					PullRequest: pr,
				})
			}

			data.PullRequestsWithContexts = pullRequestWithContexts
		}

		marshaledData, err := json.Marshal(data)
		if err != nil {
			da.log.WithError(err).Error("Error with marshalling user data.")
		}

		if v := r.URL.Query().Get("var"); v != "" {
			fmt.Fprintf(w, "var %s = ", v)
			w.Write(marshaledData)
			io.WriteString(w, ";")
		} else {
			w.Write(marshaledData)
		}
	}
}
func (da *DashboardAgent) HandlePrStatus(queryHandler PullRequestQueryHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		serverError := func(action string, err error) {
			da.log.WithError(err).Errorf("Error %s.", action)
			msg := fmt.Sprintf("500 Internal server error %s: %v", action, err)
			http.Error(w, msg, http.StatusInternalServerError)
		}

		data := UserData{
			Login: false,
		}

		// Get existing session. Invalidate everything if we fail and continue as
		// if not logged in.
		session, err := da.goac.CookieStore.Get(r, tokenSession)
		if err != nil {
			da.log.WithError(err).Info("Failed to get existing session, invalidating GitHub login session")
			if err := invalidateGitHubSession(w, r, session); err != nil {
				serverError("Failed to invalidate GitHub session", err)
				return
			}
		}

		// If access token exists, get user login using the access token. This is a
		// chance to validate whether the access token is consumable or not. If
		// not, we invalidate the sessions and continue as if not logged in.
		token, ok := session.Values[tokenKey].(*oauth2.Token)
		var user *github.User
		var botName string
		if ok && token.Valid() {
			githubClient := github.NewClient(func() []byte { return []byte(token.AccessToken) }, github.DefaultGraphQLEndpoint, github.DefaultAPIEndpoint)
			var err error
			botName, err = githubClient.BotName()
			user = &github.User{Login: botName}
			if err != nil {
				if strings.Contains(err.Error(), "401") {
					da.log.Info("Failed to access GitHub with existing access token, invalidating GitHub login session")
					if err := invalidateGitHubSession(w, r, session); err != nil {
						serverError("Failed to invalidate GitHub session", err)
						return
					}
				} else {
					serverError("Error with getting user login", err)
					return
				}
			}
		}

		if user != nil {
			login := user.Login
			data.Login = true
			// Saves login. We save the login under 2 cookies. One for the use of client to render the
			// data and one encoded for server to verify the identity of the authenticated user.
			http.SetCookie(w, &http.Cookie{
				Name:    loginSession,
				Value:   login,
				Path:    "/",
				Expires: time.Now().Add(time.Hour * 24 * 30),
				Secure:  true,
			})
			session.Values[loginKey] = login
			if err := session.Save(r, w); err != nil {
				serverError("Save oauth session", err)
				return
			}

			// Construct query
			ghc := github.NewClient(func() []byte { return []byte(token.AccessToken) }, github.DefaultGraphQLEndpoint, github.DefaultAPIEndpoint)
			query := da.ConstructSearchQuery(login)
			if err := r.ParseForm(); err == nil {
				if q := r.Form.Get("query"); q != "" {
					query = q
				}
			}
			// If neither repo nor org is specified in the search query. We limit the search to repos that
			// are configured with either Prow or Tide.
			if !queryConstrainsRepos(query) {
				for _, v := range da.repos {
					query += fmt.Sprintf(" repo:\"%s\"", v)
				}
			}
			pullRequests, err := queryHandler.QueryPullRequests(context.Background(), ghc, query)
			if err != nil {
				serverError("Error with querying user data.", err)
				return
			}
			var pullRequestWithContexts []PullRequestWithContexts
			for _, pr := range pullRequests {
				prcontexts, err := queryHandler.GetHeadContexts(ghc, pr)
				if err != nil {
					serverError("Error with getting head context of pr", err)
					continue
				}
				pullRequestWithContexts = append(pullRequestWithContexts, PullRequestWithContexts{
					Contexts:    prcontexts,
					PullRequest: pr,
				})
			}

			data.PullRequestsWithContexts = pullRequestWithContexts
		}

		marshaledData, err := json.Marshal(data)
		if err != nil {
			da.log.WithError(err).Error("Error with marshalling user data.")
		}

		if v := r.URL.Query().Get("var"); v != "" {
			fmt.Fprintf(w, "var %s = ", v)
			w.Write(marshaledData)
			io.WriteString(w, ";")
		} else {
			w.Write(marshaledData)
		}
	}
}
func ( da * DashboardAgent ) HandlePrStatus ( queryHandler PullRequestQueryHandler ) http . HandlerFunc { return func ( w http . ResponseWriter , r * http . Request ) { serverError := func ( action string , err error ) { da . log . WithError ( err ) . Errorf ( " " , action ) msg := fmt . Sprintf ( " " , action , err ) http . Error ( w , msg , http . StatusInternalServerError ) } data := UserData { Login : false , } // Get existing session. Invalidate everything if we fail and continue as // if not logged in. session , err := da . goac . CookieStore . Get ( r , tokenSession ) if err != nil { da . log . WithError ( err ) . Info ( " " ) if err := invalidateGitHubSession ( w , r , session ) ; err != nil { serverError ( " " , err ) return } } // If access token exists, get user login using the access token. This is a // chance to validate whether the access token is consumable or not. If // not, we invalidate the sessions and continue as if not logged in. token , ok := session . Values [ tokenKey ] . ( * oauth2 . Token ) var user * github . User var botName string if ok && token . Valid ( ) { githubClient := github . NewClient ( func ( ) [ ] byte { return [ ] byte ( token . AccessToken ) } , github . DefaultGraphQLEndpoint , github . DefaultAPIEndpoint ) var err error botName , err = githubClient . BotName ( ) user = & github . User { Login : botName } if err != nil { if strings . Contains ( err . Error ( ) , " " ) { da . log . Info ( " " ) if err := invalidateGitHubSession ( w , r , session ) ; err != nil { serverError ( " " , err ) return } } else { serverError ( " " , err ) return } } } if user != nil { login := user . Login data . Login = true // Saves login. We save the login under 2 cookies. One for the use of client to render the // data and one encoded for server to verify the identity of the authenticated user. http . SetCookie ( w , & http . Cookie { Name : loginSession , Value : login , Path : " " , Expires : time . Now ( ) . Add ( time . Hour * 24 * 30 ) , Secure : true , } ) session . Values [ loginKey ] = login if err := session . Save ( r , w ) ; err != nil { serverError ( " " , err ) return } // Construct query ghc := github . NewClient ( func ( ) [ ] byte { return [ ] byte ( token . AccessToken ) } , github . DefaultGraphQLEndpoint , github . DefaultAPIEndpoint ) query := da . ConstructSearchQuery ( login ) if err := r . ParseForm ( ) ; err == nil { if q := r . Form . Get ( " " ) ; q != " " { query = q } } // If neither repo nor org is specified in the search query. We limit the search to repos that // are configured with either Prow or Tide. if ! queryConstrainsRepos ( query ) { for _ , v := range da . repos { query += fmt . Sprintf ( " \" \" " , v ) } } pullRequests , err := queryHandler . QueryPullRequests ( context . Background ( ) , ghc , query ) if err != nil { serverError ( " " , err ) return } var pullRequestWithContexts [ ] PullRequestWithContexts for _ , pr := range pullRequests { prcontexts , err := queryHandler . GetHeadContexts ( ghc , pr ) if err != nil { serverError ( " " , err ) continue } pullRequestWithContexts = append ( pullRequestWithContexts , PullRequestWithContexts { Contexts : prcontexts , PullRequest : pr , } ) } data . PullRequestsWithContexts = pullRequestWithContexts } marshaledData , err := json . Marshal ( data ) if err != nil { da . log . WithError ( err ) . Error ( " " ) } if v := r . URL . Query ( ) . Get ( " " ) ; v != " " { fmt . Fprintf ( w , " " , v ) w . Write ( marshaledData ) io . WriteString ( w , " " ) } else { w . Write ( marshaledData ) } } }
// HandlePrStatus returns a http handler function that handles request to /pr-status
// endpoint. The handler takes user access token stored in the cookie to query to GitHub on behalf
// of the user and serve the data in return. The Query handler is passed to the method so as it
// can be mocked in the unit test..
HandlePrStatus returns a http handler function that handles request to / pr - status endpoint . The handler takes user access token stored in the cookie to query to GitHub on behalf of the user and serve the data in return . The Query handler is passed to the method so as it can be mocked in the unit test ..