func TestConnection()

in backend/plugins/github/api/connection.go [71:204]


func TestConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
	// process input
	var conn models.GithubConn
	e := mapstructure.Decode(input.Body, &conn)
	if e != nil {
		return nil, errors.Convert(e)
	}
	e = vld.StructExcept(conn, "GithubAppKey", "GithubAccessToken")
	if e != nil {
		return nil, errors.Convert(e)
	}

	apiClient, err := api.NewApiClientFromConnection(context.TODO(), basicRes, &conn)
	if err != nil {
		return nil, err
	}

	githubApiResponse := &GithubTestConnResponse{}

	if conn.AuthMethod == "AppKey" {
		jwt, err := conn.GithubAppKey.CreateJwt()
		if err != nil {
			return nil, err
		}

		res, err := apiClient.Get("app", nil, http.Header{
			"Authorization": []string{fmt.Sprintf("Bearer %s", jwt)},
		})

		if err != nil {
			return nil, errors.BadInput.Wrap(err, "verify token failed")
		}
		if res.StatusCode != http.StatusOK {
			return nil, errors.HttpStatus(res.StatusCode).New("unexpected status code while testing connection")
		}

		githubApp := &models.GithubApp{}
		err = api.UnmarshalResponse(res, githubApp)
		if err != nil {
			return nil, errors.BadInput.Wrap(err, "verify token failed")
		} else if githubApp.Slug == "" {
			return nil, errors.BadInput.Wrap(err, "invalid token")
		}

		res, err = apiClient.Get("app/installations", nil, http.Header{
			"Authorization": []string{fmt.Sprintf("Bearer %s", jwt)},
		})

		if err != nil {
			return nil, errors.BadInput.Wrap(err, "verify token failed")
		}
		if res.StatusCode != http.StatusOK {
			return nil, errors.HttpStatus(res.StatusCode).New("unexpected status code while testing connection")
		}

		githubAppInstallations := &[]models.GithubAppInstallation{}
		err = api.UnmarshalResponse(res, githubAppInstallations)
		if err != nil {
			return nil, errors.BadInput.Wrap(err, "verify token failed")
		}

		githubApiResponse.Success = true
		githubApiResponse.Message = "success"
		githubApiResponse.Login = githubApp.Slug
		githubApiResponse.Installations = *githubAppInstallations

	} else if conn.AuthMethod == "AccessToken" {
		res, err := apiClient.Get("user", nil, nil)
		if err != nil {
			return nil, errors.BadInput.Wrap(err, "verify token failed")
		}

		if res.StatusCode == http.StatusUnauthorized {
			return nil, errors.HttpStatus(http.StatusBadRequest).New("StatusUnauthorized error when testing connection")
		}

		if res.StatusCode != http.StatusOK {
			return nil, errors.HttpStatus(res.StatusCode).New("unexpected status code while testing connection")
		}

		githubUserOfToken := &models.GithubUserOfToken{}
		err = api.UnmarshalResponse(res, githubUserOfToken)
		if err != nil {
			return nil, errors.BadInput.Wrap(err, "verify token failed")
		} else if githubUserOfToken.Login == "" {
			return nil, errors.BadInput.Wrap(err, "invalid token")
		}

		success := false
		warning := false
		messages := []string{}
		// for github classic token, check permission
		if strings.HasPrefix(conn.Token, "ghp_") {
			scopes := res.Header.Get("X-OAuth-Scopes")
			// convert "X-OAuth-Scopes" header to user permissions map
			userPerms := map[string]bool{}
			for _, userPerm := range strings.Split(scopes, ", ") {
				userPerms[userPerm] = true
			}
			// check public repo permission
			missingPubPerms := findMissingPerms(userPerms, publicPermissions)
			success = len(missingPubPerms) == 0
			if !success {
				messages = append(messages, fmt.Sprintf(
					"Please check the field(s) %s",
					strings.Join(missingPubPerms, ", "),
				))
			}
			// check private repo permission
			missingPriPerms := findMissingPerms(userPerms, privatePermissions)
			warning = len(missingPriPerms) > 0
			if warning {
				msgFmt := "If you want to collect private repositories, please check the field(s) %s"
				if success {
					// @Startrekzky and @yumengwang03 firmly believe that this is critical for users to understand the message
					msgFmt = "This token is able to collect public repositories. " + msgFmt
				}
				messages = append(messages, fmt.Sprintf(
					msgFmt,
					strings.Join(missingPriPerms, ", "),
				))
			}
		}

		githubApiResponse.Success = success
		githubApiResponse.Warning = warning
		githubApiResponse.Message = strings.Join(messages, ";\n")
		githubApiResponse.Login = githubUserOfToken.Login
	} else {
		return nil, errors.BadInput.New("invalid authentication method")
	}

	return &plugin.ApiResourceOutput{Body: githubApiResponse, Status: http.StatusOK}, nil
}